In this exercise, we will pull together many aspects of what we have
learned so far to calibrate the HBV model to weighted data from the
Fraser Experimental Forest in Colorado using precipitation/runoff and
potential evapotranspiration (PET) data derived from the methods
explored in the snowmelt and evapotranspiration modules.
HBV is: In the previous labs, we have worked with single-process
models. HBV is more complex process-based model using many parameters to
describe the physical processes of the hydrologic cycle https://rpubs.com/sdhakal/848236
HBV versions with a GUI exists, but the data manipulation is more
convenient in a coding environment, and we want you to be able to see
‘under the hood’. Instead of dealing with the inner workings of the
model too much, we will put the focus on importing and organizing the
data, getting the model running, manual optimization.
The HBV realization we will be using is contained in the R package
TUWmodel. Please search that package in your browser and familiarize
yourself with it (that will be the first step). TUW simply means
“Technische Universitaet Wien”, or Vienna University of Technology. The
model is slightly different from the original HBV but still similar
enough to call it HBV. We also need to understand the arguments and
parmeters required for the model.
Type ‘?TUWmodel’ in your console. Note that the package comes with an
example dataset, and you can run examples either by copying and pasting
the data(), TUWmodel() and plots into your console, or you can find and
click ‘Run examples’ under the Examples header and view
the script and plot outputs in the Help window. The first example shows
how the ‘TUWmodel’ can be run given specifications for a long set of
parameters (param). You can provide the model with precip, air
temperature, area and ET along with the parameter set and it will
simulate SWE, snowmelt and discharge. We can obtain measurements for
each of these variables, so we will import all of this data and test the
fit of the simulated data.
Labwork (20 pnts)
Our first steps will be to import and format the data. As you might
recall from the previous modules, this step can require the most script
and ‘work’, but is critical to a valid model output. In this assignment,
we have simplified much of the data collection for you, as the steps are
ones you have already completed in previous modules. In the .csv
imported below, we started by collecting the same SNOTEL data that you
used in the snowmelt module, but downloaded for a greater date range
(water years 2018-2022) (date, SWE depth in mm, and daily precipitation
(mm)) However, you will notice that the column names of the provided
table contain ‘weighted_’.
#rm(list = ls()) # this clears out the Environment ("fresh start!")
#indata <- read_csv("FEF_lumped_daily_2020_2023.csv")
indata <- read.csv("HBV_data/weighted_data_fool_HBV.csv")%>%
mutate(date = ymd(date)) %>%
rename(Q_m3_s = m3_s, Q_mm_day = mm_day, runoff_input.mm = input.mm )
str(indata)
'data.frame': 1826 obs. of 17 variables:
$ date : Date, format: "2017-10-01" ...
$ wtr_yr : int 2018 2018 2018 2018 2018 2018 2018 2018 2018 2018 ...
$ weighted_swe.mm : num 13.3 46.7 53.4 53.4 51.2 ...
$ weighted_precip.mm: num 26.78 7.65 1.91 0 0 ...
$ weighted_pcumul.mm: num 26.8 34.4 36.3 36.3 36.3 ...
$ Q_m3_s : num 0.00862 0.00743 0.00715 0.00704 0.00704 ...
$ Q_mm_day : num 0.282 0.243 0.234 0.23 0.231 ...
$ Tmax_c : num 5.55 1.95 5.25 12.75 12.75 ...
$ Tmean_c : num 0.8 -1.6 -0.7 6.2 6.65 0.25 3.2 2.5 -7.8 -1.8 ...
$ Tmin_c : num -3.95 -5.15 -6.65 -0.35 0.55 ...
$ RHmin : num 43.1 60.3 41.2 28.9 27.4 ...
$ RHmax : num 90.6 91.8 91.2 86 78.6 ...
$ month : int 10 10 10 10 10 10 10 10 10 10 ...
$ day : int 1 2 3 4 5 6 7 8 9 10 ...
$ SWEdiff.mm : num 0 33.38 6.75 0 -2.28 ...
$ Pdiff.mm : num 0 7.65 1.91 0 0 ...
$ runoff_input.mm : num 0 0 0 0 2.28 ...
As we noted in the Snowmelt module, factors such as elevation and
vegetation will affect the of snow-to-runoff rate. Similarly,
temperature and precipitation differ with elevation, meaning that SNOTEL
data from a single location may not fully represent conditions across
the entire watershed.
To account for these variations, the “weighted” values for this
exercise have been adjusted using linear scaling relationships that
estimate average conditions across the watershed. The adjustments use
elevation-precipitation and elevation-temperature relationships derived
from inverse distance weighting to better approximate spatially
distributed hydrological inputs rather than relying on a single point
measurement.
/precip_spatial_interp.png
If you are interested, you can start exploring spatial interpolation
with: 1. Thiessen polygons
2. Inverse distance weighting 3. Kringing
methods to determine if any of these are applicable to your study
area.
Other columns in this data include: Q_m3_s and
Q_mm_day - Discharge (Q) collected at the Fool Creek outlet by
USFS, in units of cubic meters per second and mm per day from April
until October. Tmax_c, Tmin_c and Tmean_c - Typically,
we could find daily mean, max and minimum temperatures in the SNOTEL
datasets, however, this particular station is missing temperature data
(due to restrictions on technical access in 2020), so we retrieved
temperature data from GridMET through Climate Engine.
This highlights the importance of evaluating each variable for
completeness. It will save you the headache of running the entire
workflow, only to find that model outputs cannot be simulated for the
later half of 2020 due to missing input data. RHmin,
RHmax - Relative humidity daily min and max, also from GridMET,
accessed through Climate Engine SWEdiff.mm, Pdiff.mm and
runoff_input.mm - all daily outputs of a temperature based
snowmelt model (the same as in the snowmelt module). runoff_input is the
estimated daily input to the stream from melted snow and liquid
precipitation combined.
Q1 (4 pnts) Generate script (including plots) that can be
used to evaluate the structure of the dataset and the duration and
consistency of the data. The submitted plot should show at least two
time series of ‘indata’ (2 variables on y, date on x), but be sure to
check every column for yourself. Do you see any potential issues like
missing data or unexpected values? ANSWER:
Keep in mind that you can plot more than two variables in a single
plot, but they will be most helpful if you group variables with a
similar y-scale. For example, cumulative precipitation or SWE values
will have a different range than variables that represent daily
measurements like ‘input_mm’. Alternatively, you can add a secondary
y-axis to your plot.
BLANK +
geom_point(aes(x = date, y = runoff_input.mm, color = "runoff_input.mm"), size = 0.5) + # Assign a label for legend
geom_point(aes(x = date, y = Q_mm_day, color = "mm/day"), size = 0.5) + # Assign a different label
geom_point(aes(x = date, y = weighted_precip.mm, color = "weighted_precip.mm"), size = 0.5) + # Assign a different label
BLANK(aes(x = date, y = Pdiff.mm, color = "Pdiff.mm"), size = 0.5) +
scale_color_manual(values = c("runoff_input.mm" = "blue", "mm/day" = "red", "weighted_precip.mm" = "green", "Pdiff.mm" = 'purple')) + # Customize colors
labs(color = "Discharge Units") + # Legend title
theme_minimal()
Error: object 'BLANK' not found
2,930m. watershed_area_m2 <- 2640000
Note that while the stream is snow-covered, there are no stage/flow
measurements being made at this site. For many of our calculations to
work, we will not want NA in our data frames. In this data set, if we
view the tabular data, the end discharge reading (Q_mm_day), is very
similar to the first in the following calendar year. For this example,
we will then fill the NA values with the mean of the final and first
readings for each winter (Oct - April) NA string.
Let’s try our quick check again:
Next, we need to add daily potential evapotranspiration (PET) to the
dataset. The evapotranspiration module covered some of the numerous
pre-built functions available in various R packages designed for ET
estimation. For instance, the ‘Evapotranspiration’ package provides ET
estimates derived from approximately 20 distinct equations or
variations. These functions require precise data formatting to ensure
compatibility with the function arguments. To help you structure your
function inputs similarly, many packages come with example datasets in
their documentation. SPEI is another package that offers ET functions.
The github repository for this package has been updated fairly recently,
which can be important to verify.
We chose to write our own function here so you could ‘see under the
hood’.
Not all packages are equally maintained, as they are often developed by
researchers or modelers to improve the repeatably of their work, and
contribute to the broader scientific community. Once funding ceases, or
if the original developer moves on to new projects, a custom package may
no longer receive updates or support. As R, RStudio and other supporting
packages are updated, a package may become depreciated. If the package
still functions correctly in your current R version and dependencies,
there’s no immediate reason to stop using it. However, if you are
concerned that future versions of R or dependencies might break the
packages you use, you can check the development and maintenance history
of custom or specialized packages (or write a package or function for
yourself as exemplified below!).
Here is our Hargreaves function, adapted from the
‘Evapotranspiration’ package to minimize re-formatting of our
dataframe.
Now we will format the inputs so the data is easily read by the
function, and run the function.
Now we’ll add daily ET into our original dataframe:
Q2. (4 pts) Generate a summary dataframe that summarizes
columns of ‘indata’ by water year and helps you evaluate the water
balance for each year. (I recommend summarizing SWE, precipitation,
runoff input, discharge, and PET) Make sure your summary makes
sense. For example, some variables are most useful when summarized as a
mean, while others are more helpful when viewed as an annual sum,
minimum or maximum. If you are unsure of where to start, try using using
group_by() and summarize().
Q3 (3 pts) The provided PET data was calculated just using
min and max daily air temperature using a Hargreaves approach. View your
annual totals for PET and compare it to the amount of precipitation. Are
those values reasonable? What can you say about the timing of water
demand (PET) and availability (melt and rain)? IMPORTANT: Use
runoff_input_mm here and explain why it wouldn’t make sense to use
weighted_precip.mm.
ANSWER:
By subtracting discharge and PET from runoff_input, we’re essentially
examining the residual water. This could represent the amount of water
available to the system after accounting for the demand (PET) and the
outflow (discharge).
Q4 (4pnts) Consider the evapotranspiration module and the
discussion potential and actual evapotranspiration. Why do you think PET
yields estimates of negative residual water in this high elevation,
semi-arid system? ANSWER:
Again, you may have to change some of the script below to accommodate
your summary dataframe, and not every column will be helpful for a
synopsis figure, but the objective in this chunk is to present the
column values of your summary dataframe as a bar chart.
single model execution
Objective functions
KGE
Before we can start trying to tune our model to look more like the
observed discharge record, it would be helpful to have some sort of
quantified metric for how well our modeled data fits the measured
data.
There are many different ways to do this, but discussion of the pros
and cons of those approaches is beyond this quick introduction to
modeling.
Here we will demonstrate the Kling-Gupta efficiency both for runoff
as well as for swe.
NSE
Nash-Sutcliffe Efficiency (NSE).
Basically, the NSE looks at how much better your model run did that
if you had just used the mean discharge for the data record as your
“modelled results”. It does this by comparing how far off the observed
values where from the mean discharge to how far off the modeled values
were from the observed discharge.
Mathematically, NSE is the sum of the squared differences between the
modeled and observed discharge divided by the sum of the squared
differences between the observed and mean discharge, subtracted by
1.
\[
NSE = 1 - \frac{\sum_{t = 1}^{T}{(Q_m^t - Q_o^t)^2}}{\sum_{t =
1}^{T}{(Q_o^t - \bar{Q_o})^2}}
\] Where \(Q_m^t\) is modeled
discharge at time t, \(Q_o^t\) is
observed discharge at time t, and \(\bar{Q_o}\) is mean observed discharge.
Calibrate HBV manually
Woohoo! We can now run our model and assess how well it is
working!
Now, let’s see how well we can get it to work. The code below runs
the model, produces a plot, and calculates the NSE based on
discharge.
# set up the parameter vector
model_params <- c(
1.05, # SCF snow correction factor [-] (e.g., 0.9-1.5);
1.80, # DDF degree day factor [mm/degC/timestep] (e.g., 0.0-5.0 mm/degC/day);
2, # Tr threshold temperature above which precipitation is rain [degC] (e.g., 1.0-3.0 degC);
0, # Ts threshold temperature below which precipitation is snow [degC] (e.g., -3.0-1.0 degC);
-0.336, # Tm threshold temperature above which melt starts [degC] (e.g., -2.0-2.0 degC);
0.2, # LPrat parameter related to the limit for potential evaporation [-] (e.g., 0.0-1.0);
121, # FC field capacity, i.e., max soil moisture storage [mm] (e.g., 0-600 mm);
2.52, # BETA the non linear parameter for runoff production [-] (e.g., 0.0-20.0);
0.473, # k0 storage coefficient for very fast response [timestep] (e.g., 0.0-2.0 days);
9.06, # k1 storage coefficient for fast response [timestep] (e.g., 2.0-30.0 days);
142, # k2 storage coefficient for slow response [timestep] (e.g., 30.0-250.0 days);
50.1, # lsuz threshold storage state, i.e., the very fast response start if exceeded [mm] (e.g., 1.0-100.0 mm);
2.38, # cperc constant percolation rate [mm/timestep] (e.g., 0.0-8.0 mm/day);
10, # bmax maximum base at low flows [timestep] (e.g., 0.0-30.0 days);
25 # croute free scaling parameter [timestep^2/mm] (e.g., 0.0-50.0 days^2/mm);
)
# set time period
model_in <- indata %>%
filter(date >= as_date("2017-10-01") & date <= as_date("2022-09-30"))
# set up the model
## THIS IS THE ACTUAL MODEL EXECUTION
modelRun <- TUWmodel(
prec = model_in$weighted_precip.mm, # precip input
airt = model_in$Tmean_c, # air temp input
ep = model_in$PET_mm, # pet input
area = 1, # one zone for the entire watershed
param = model_params # input model parameters
)
# get all outputs into a nice df
HBVRun <- tibble(
Date = model_in$Date, # date
P_mm = modelRun$prec, # precip
Tair = modelRun$airt, # air temp
SWEobs = model_in$weighted_swe.mm, # observed swe
PET = modelRun$ep,# pet
Qobs = model_in$Q_mm_day, # observed discharge
Qsim = modelRun$q[1, ], # simulated discharge
Qsurf = modelRun$q0[1, ], # surface runoff
Qsubsurf = modelRun$q1[1, ], # subsurface flow
Qbase = modelRun$q2[1, ], # groundwater flow
Rain = modelRun$rain[1, ], # simulated rain
Snow = modelRun$snow[1, ], # simulated snowfall
Melt = modelRun$melt[1, ], # simulated melt
SWEsim = modelRun$swe[1, ], # simulated swe
Soilmoist = modelRun$moist[1, ], # simulated soil storage
AET = modelRun$eta[1, ], # simulated evapotranspiration
StorageUpper = modelRun$suz[1, ], # upper storage value
StorageLower = modelRun$slz[1, ] # lower storage value
)
#Trim out the warm up period
OutTrim <- HBVRun %>% slice(366:n())
#Calculate NSE
NSE <- 1 - ((sum((OutTrim$Qsim - OutTrim$Qobs) ^ 2)) /
sum((OutTrim$Qobs - mean(OutTrim$Qobs)) ^ 2))
print(NSE)
[1] -0.3496303
Plot observed and model simulations
Generate plots that include and compare the different modeled fluxes
from your best NSE. Some of those fluxes can be immediately compared to
observed data (e.g., runoff or SWE), while others only exist in
simulated form (e.g., storages or outflows of the various runoff
components) and need to be assessed with the perceptual model in
mind.
Make sure that the axes are properly labeled when you create plots. The
script below will get you started.
# Add date to the HBVRun result tibble
HBVRun <- as.data.frame(HBVRun)
HBVRun$Date <- model_in$date
str(HBVRun)
'data.frame': 1826 obs. of 18 variables:
$ P_mm : num 26.78 7.65 1.91 0 0 ...
$ Tair : num 0.8 -1.6 -0.7 6.2 6.65 0.25 3.2 2.5 -7.8 -1.8 ...
$ SWEobs : num 13.3 46.7 53.4 53.4 51.2 ...
$ PET : num 1.3 1.15 1.23 1.84 1.76 ...
$ Qobs : num 0.282 0.243 0.234 0.23 0.231 ...
$ Qsim : num 0.0135 0.0418 0.0661 0.0531 0.0398 ...
$ Qsurf : num 0 0 0 0 0 0 0 0 0 0 ...
$ Qsubsurf : num 0.1343 0 0 0 0.0421 ...
$ Qbase : num 0.0342 0.0434 0.0431 0.0569 0.0732 ...
$ Rain : num 10.7 0 0 0 0 ...
$ Snow : num 16.07 7.65 1.91 0 0 ...
$ Melt : num 2.04 0 0 11.76 12.57 ...
$ SWEsim : num 14.825 22.858 24.866 13.101 0.526 ...
$ Soilmoist : num 60.1 60.1 60.1 68 75.9 ...
$ AET : num 1.3 0 0 1.84 1.76 ...
$ StorageUpper: num 1.36 0 0 0 0.52 ...
$ StorageLower: num 4.85 6.16 6.12 8.08 10.39 ...
$ Date : Date, format: "2017-10-01" ...
# Round the NSE for display
nse_label <- paste("NSE =", round(NSE, 3))
q_plot <- ggplot(data = HBVRun) +
geom_line(aes(x = Date, y = Qobs, color = "Qobs")) + # Qobs
geom_line(aes(x = Date, y = Qsim, color = "Qsim")) + # Qsim
annotate("text",
x = max(HBVRun$Date) - 100, # Move label # days from the end
y = max(HBVRun$Qobs, na.rm = TRUE),
label = nse_label,
hjust = 1, vjust = 1.5, size = 5, fontface = "bold") +
labs(x = NULL, y = "Q (mm/day)", color = NULL, title = "Qobs and Qsim")
# Make it interactive with plotly
ggplotly(q_plot)
NA
Q6. (5 pts) What is the role of the model parameters in
representing hydrological processes? What is one effective method to
calibrate these parameters without relying on manual
adjustment?
Answer:
More exploratory/demonstrative plots
# Swe
swe_plot <- ggplot(data = HBVRun) +
geom_line(aes(x = Date, y = SWEobs, color = "SWEobs")) + # SWEobs
geom_line(aes(BLANK)) + # SWEsim
labs(x = {}, y = "SWE (mm)", color = {})
ggplotly(swe_plot)
Error: object 'BLANK' not found
# Q0, Q1, Q2
q_bucket_plot <- ggplot(data = HBVRun) +
geom_line(aes(x = Date, y = Qsurf, color = "Qsurf")) + # Qsurf
geom_line(aes(x = Date, y = Qsubsurf, color = "Qsubsurf")) + #Qsubsurf
geom_line(aes(x = Date, y = Qbase, color = "Qbase")) + # Qbase
labs(x = {}, y = "Q (mm)", color = {}, title = "Q0, Q1, and Q2")
ggplotly(q_bucket_plot)
# PET and AET
pet_plot <- ggplot(data = HBVRun) +
geom_line(aes(x = Date, y = PET, color = "PET")) + # PET
geom_line(aes(x = Date, y = AET, color = "AET")) + # AET
labs(x = {}, y = "Flux (mm)", color = {}, title = "PET and AET")
ggplotly(pet_plot)
# Storages
storage_plot <- ggplot(data = HBVRun) +
geom_line(aes(x = Date, y = Soilmoist, color = "Soil moisture storage")) + # soil moisture storage
geom_line(aes(x = Date, y = StorageUpper, color = "Upper storage")) + # upper storage
geom_line(aes(x = Date, y = StorageLower, color = "Lower storage")) + # lower storage
labs(x = {}, y = "Storage (mm)", color = {}, title = "Storages")
ggplotly(storage_plot)
LS0tCnRpdGxlOiAiSEJWIE1vZGVsIgphdXRob3I6ICJZT1VSIE5BTUUgSEVSRSIKb3V0cHV0OiBodG1sX25vdGVib29rCmVkaXRvcl9vcHRpb25zOiAKICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKCiNMb2FkIHBhY2thZ2VzCiMgcGtnVGVzdCBpcyBhIGhlbHBlciBmdW5jdGlvbiB0byBsb2FkIHBhY2thZ2VzIGFuZCBpbnN0YWxsIHBhY2thZ2VzIG9ubHkgd2hlbiB0aGV5IGFyZSBub3QgaW5zdGFsbGVkIHlldC4KCnBrZ1Rlc3QgPC0gZnVuY3Rpb24oeCkKewogIGlmICh4ICVpbiUgcm93bmFtZXMoaW5zdGFsbGVkLnBhY2thZ2VzKCkpID09IEZBTFNFKSB7CiAgICBpbnN0YWxsLnBhY2thZ2VzKHgsIGRlcGVuZGVuY2llcz0gVFJVRSkKICB9CiAgbGlicmFyeSh4LCBjaGFyYWN0ZXIub25seSA9IFRSVUUpCn0KbmVlZGVkUGFja2FnZXMgPC0gYygidGlkeXZlcnNlIiwgImx1YnJpZGF0ZSIsICJicm9vbSIsICJUVVdtb2RlbCIsICJwbG90bHkiKSAKCmZvciAocGFja2FnZSBpbiBuZWVkZWRQYWNrYWdlcyl7cGtnVGVzdChwYWNrYWdlKX0KYGBgCgpJbiB0aGlzIGV4ZXJjaXNlLCB3ZSB3aWxsIHB1bGwgdG9nZXRoZXIgbWFueSBhc3BlY3RzIG9mIHdoYXQgd2UgaGF2ZSBsZWFybmVkIHNvIGZhciB0byBjYWxpYnJhdGUgdGhlIEhCViBtb2RlbCB0byB3ZWlnaHRlZCBkYXRhIGZyb20gdGhlIEZyYXNlciBFeHBlcmltZW50YWwgRm9yZXN0IGluIENvbG9yYWRvIHVzaW5nIHByZWNpcGl0YXRpb24vcnVub2ZmIGFuZCBwb3RlbnRpYWwgZXZhcG90cmFuc3BpcmF0aW9uIChQRVQpIGRhdGEgZGVyaXZlZCBmcm9tIHRoZSBtZXRob2RzIGV4cGxvcmVkIGluIHRoZSBzbm93bWVsdCBhbmQgZXZhcG90cmFuc3BpcmF0aW9uIG1vZHVsZXMuIAoKSEJWIGlzOgpJbiB0aGUgcHJldmlvdXMgbGFicywgd2UgaGF2ZSB3b3JrZWQgd2l0aCBzaW5nbGUtcHJvY2VzcyBtb2RlbHMuIEhCViBpcyBtb3JlIGNvbXBsZXggcHJvY2Vzcy1iYXNlZCBtb2RlbCB1c2luZyBtYW55IHBhcmFtZXRlcnMgdG8gZGVzY3JpYmUgdGhlIHBoeXNpY2FsIHByb2Nlc3NlcyBvZiB0aGUgaHlkcm9sb2dpYyBjeWNsZQpodHRwczovL3JwdWJzLmNvbS9zZGhha2FsLzg0ODIzNgoKIVtdKGltYWdlcy9IQlYtc2NoZW0tU2hyZXN0aGEtU29sb21hbnRpbmUtMjAwOC5wbmcgIkhCViBNb2RlbCIpClRoaXMgc2NoZW1hdGljIHdhcyByZXByb2R1Y2VkIGZyb206IER1cmdhIExhbCBTaHJlc3RoYSAmIERpbWl0cmkgUC4gU29sb21hdGluZSAoMjAwOCkgRGF0YeKAkGRyaXZlbiBhcHByb2FjaGVzIGZvciBlc3RpbWF0aW5nIHVuY2VydGFpbnR5IGluIHJhaW5mYWxs4oCQcnVub2ZmIG1vZGVsbGluZywgSW50ZXJuYXRpb25hbCBKb3VybmFsIG9mIFJpdmVyIEJhc2luIE1hbmFnZW1lbnQsIDY6MiwgMTA5LTEyMiwgRE9JOiAxMC4xMDgwLzE1NzE1MTI0LjIwMDguOTYzNTM0MQoKSEJWIHZlcnNpb25zIHdpdGggYSBHVUkgZXhpc3RzLCBidXQgdGhlIGRhdGEgbWFuaXB1bGF0aW9uIGlzIG1vcmUgY29udmVuaWVudCBpbiBhIGNvZGluZyBlbnZpcm9ubWVudCwgYW5kIHdlIHdhbnQgeW91IHRvIGJlIGFibGUgdG8gc2VlICd1bmRlciB0aGUgaG9vZCcuIEluc3RlYWQgb2YgZGVhbGluZyB3aXRoIHRoZSBpbm5lciB3b3JraW5ncyBvZiB0aGUgbW9kZWwgdG9vIG11Y2gsIHdlIHdpbGwgcHV0IHRoZSBmb2N1cyBvbiBpbXBvcnRpbmcgYW5kIG9yZ2FuaXppbmcgdGhlIGRhdGEsIGdldHRpbmcgdGhlIG1vZGVsIHJ1bm5pbmcsIG1hbnVhbCBvcHRpbWl6YXRpb24uICAKClRoZSBIQlYgcmVhbGl6YXRpb24gd2Ugd2lsbCBiZSB1c2luZyBpcyBjb250YWluZWQgaW4gdGhlIFIgcGFja2FnZSBUVVdtb2RlbC4gUGxlYXNlIHNlYXJjaCB0aGF0IHBhY2thZ2UgaW4geW91ciBicm93c2VyIGFuZCBmYW1pbGlhcml6ZSB5b3Vyc2VsZiB3aXRoIGl0ICh0aGF0IHdpbGwgYmUgdGhlIGZpcnN0IHN0ZXApLiBUVVcgc2ltcGx5IG1lYW5zICJUZWNobmlzY2hlIFVuaXZlcnNpdGFldCBXaWVuIiwgb3IgVmllbm5hIFVuaXZlcnNpdHkgb2YgVGVjaG5vbG9neS4gVGhlIG1vZGVsIGlzIHNsaWdodGx5IGRpZmZlcmVudCBmcm9tIHRoZSBvcmlnaW5hbCBIQlYgYnV0IHN0aWxsIHNpbWlsYXIgZW5vdWdoIHRvIGNhbGwgaXQgSEJWLiBXZSBhbHNvIG5lZWQgdG8gdW5kZXJzdGFuZCB0aGUgYXJndW1lbnRzIGFuZCBwYXJtZXRlcnMgcmVxdWlyZWQgZm9yIHRoZSBtb2RlbC4gCgpUeXBlICc/VFVXbW9kZWwnIGluIHlvdXIgY29uc29sZS4gTm90ZSB0aGF0IHRoZSBwYWNrYWdlIGNvbWVzIHdpdGggYW4gZXhhbXBsZSBkYXRhc2V0LCBhbmQgeW91IGNhbiBydW4gZXhhbXBsZXMgZWl0aGVyIGJ5IGNvcHlpbmcgYW5kIHBhc3RpbmcgdGhlIGRhdGEoKSwgVFVXbW9kZWwoKSBhbmQgcGxvdHMgaW50byB5b3VyIGNvbnNvbGUsIG9yIHlvdSBjYW4gZmluZCBhbmQgY2xpY2sgJ1J1biBleGFtcGxlcycgdW5kZXIgdGhlICoqRXhhbXBsZXMqKiBoZWFkZXIgYW5kIHZpZXcgdGhlIHNjcmlwdCBhbmQgcGxvdCBvdXRwdXRzIGluIHRoZSBIZWxwIHdpbmRvdy4gVGhlIGZpcnN0IGV4YW1wbGUgc2hvd3MgaG93IHRoZSAgJ1RVV21vZGVsJyBjYW4gYmUgcnVuIGdpdmVuIHNwZWNpZmljYXRpb25zIGZvciBhIGxvbmcgc2V0IG9mIHBhcmFtZXRlcnMgKHBhcmFtKS4gWW91IGNhbiBwcm92aWRlIHRoZSBtb2RlbCB3aXRoIHByZWNpcCwgYWlyIHRlbXBlcmF0dXJlLCBhcmVhIGFuZCBFVCBhbG9uZyB3aXRoIHRoZSBwYXJhbWV0ZXIgc2V0IGFuZCBpdCB3aWxsIHNpbXVsYXRlIFNXRSwgc25vd21lbHQgYW5kIGRpc2NoYXJnZS4gV2UgY2FuIG9idGFpbiBtZWFzdXJlbWVudHMgZm9yIGVhY2ggb2YgdGhlc2UgdmFyaWFibGVzLCBzbyB3ZSB3aWxsIGltcG9ydCBhbGwgb2YgdGhpcyBkYXRhIGFuZCB0ZXN0IHRoZSBmaXQgb2YgdGhlIHNpbXVsYXRlZCBkYXRhLiAKCmh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9UVVdtb2RlbC9UVVdtb2RlbC5wZGYgIAoKIyMjIEltcG9ydCBkYXRhOiAKV2Ugd2lsbCBnZW5lcmF0ZSBhIGNvbmNlcHR1YWwgcnVub2ZmIG1vZGVsIHN0YXJ0aW5nIHdpdGg6PGJyPgotIFJhaW5NZWx0V2VpZ2h0ZWRfbW0gLS0+IGxpcXVpZCBpbnB1dCB0byB0aGUgZ3JvdW5kLCBjb21iaW5hdGlvbiBvZiByYWluIGFuZCBtZWx0PGJyPgotIFBXZWlnaHRlZF9tbSAtLT4gUHJlY2lwaXRhdGlvbiBtZWFzdXJlZCBhdCB0aGUgU05PVEVMIHNpdGVzLCBib3RoIGxpcXVpZCBhbmQgZnJvemVuLiBUaGlzIGlzIE5PVCB3YXRlciB0aGF0IHdlbnQgaW50byB0aGUgZ3JvdW5kIGF0IHRoYXQgcG9pbnQuIFRoaXMgaXMsIGhvd2V2ZXIsIHRoZSBQIGlucHV0IHRpbWUgc2VyaWVzIGZvciB0aGUgSEJWIG1vZGVsLjxicj4KLSBTd2VXZWlnaHRlZF9tbSAtLT4gU25vdyB3YXRlciBlcXVpdmFsZW50IGF0IHRoZSBTTk9URUwgc2l0ZXMuIFdlIGNhbiB1c2UgdGhpcyB0byBldmFsdWF0ZSBvdXIgc25vdyByb3V0aW5lLjxicj4KLSBUZW1wV2VpZ2h0ZWQgLS0+IEVpdGhlciBkYWlseSBtZWFuLCBtaW4sIG9yIG1heC4gV2Ugd2lsbCB1c2UgdGhlIG1lYW4uCi0gRGlzY2hhcmdlX21tIC0tPiBRIG9ic2VydmVkIGF0IHRoZSBvdXRsZXQuPGJyPgotIEVUIC0tPiBQb3RlbnRpYWwgRXZhcG90cmFuc3BpcmF0aW9uIGNhbGN1bGF0ZWQgdXNpbmcgcmVsYXRpdmUgaHVtaWRpdHkgYW5kIHRlbXBlcmF0dXJlLjxicj4KCiMjIyBSZXBvIGxpbmsKW0Rvd25sb2FkIHRoZSByZXBvIGZvciB0aGlzIGxhYiBIRVJFXShodHRwczovL2dpdGh1Yi5jb20vdHBjb3Zpbm8vMDhfaGJ2X21vZGVscy0uZ2l0KXt0YXJnZXQ9Il9ibGFuayJ9CgojIyMgTGFid29yayAoMjAgcG50cykKCk91ciBmaXJzdCBzdGVwcyB3aWxsIGJlIHRvIGltcG9ydCBhbmQgZm9ybWF0IHRoZSBkYXRhLiBBcyB5b3UgbWlnaHQgcmVjYWxsIGZyb20gdGhlIHByZXZpb3VzIG1vZHVsZXMsIHRoaXMgc3RlcCBjYW4gcmVxdWlyZSB0aGUgbW9zdCBzY3JpcHQgYW5kICd3b3JrJywgYnV0IGlzIGNyaXRpY2FsIHRvIGEgdmFsaWQgbW9kZWwgb3V0cHV0LiBJbiB0aGlzIGFzc2lnbm1lbnQsIHdlIGhhdmUgc2ltcGxpZmllZCBtdWNoIG9mIHRoZSBkYXRhIGNvbGxlY3Rpb24gZm9yIHlvdSwgYXMgdGhlIHN0ZXBzIGFyZSBvbmVzIHlvdSBoYXZlIGFscmVhZHkgY29tcGxldGVkIGluIHByZXZpb3VzIG1vZHVsZXMuIApJbiB0aGUgLmNzdiBpbXBvcnRlZCBiZWxvdywgd2Ugc3RhcnRlZCBieSBjb2xsZWN0aW5nIHRoZSBzYW1lIFNOT1RFTCBkYXRhIHRoYXQgeW91IHVzZWQgaW4gdGhlIHNub3dtZWx0IG1vZHVsZSwgYnV0IGRvd25sb2FkZWQgZm9yIGEgZ3JlYXRlciBkYXRlIHJhbmdlICh3YXRlciB5ZWFycyAyMDE4LTIwMjIpIChkYXRlLCBTV0UgZGVwdGggaW4gbW0sIGFuZCBkYWlseSBwcmVjaXBpdGF0aW9uIChtbSkpIEhvd2V2ZXIsIHlvdSB3aWxsIG5vdGljZSB0aGF0IHRoZSBjb2x1bW4gbmFtZXMgb2YgdGhlIHByb3ZpZGVkIHRhYmxlIGNvbnRhaW4gJ3dlaWdodGVkXycuIAoKYGBge3J9CiNybShsaXN0ID0gbHMoKSkgIyB0aGlzIGNsZWFycyBvdXQgdGhlIEVudmlyb25tZW50ICgiZnJlc2ggc3RhcnQhIikKI2luZGF0YSA8LSByZWFkX2NzdigiRkVGX2x1bXBlZF9kYWlseV8yMDIwXzIwMjMuY3N2IikKCmluZGF0YSA8LSByZWFkLmNzdigiSEJWX2RhdGEvd2VpZ2h0ZWRfZGF0YV9mb29sX0hCVi5jc3YiKSU+JQogIG11dGF0ZShkYXRlID0geW1kKGRhdGUpKSAlPiUKICByZW5hbWUoUV9tM19zID0gbTNfcywgUV9tbV9kYXkgPSBtbV9kYXksIHJ1bm9mZl9pbnB1dC5tbSA9IGlucHV0Lm1tICkKCnN0cihpbmRhdGEpCmBgYAoKQXMgd2Ugbm90ZWQgaW4gdGhlIFNub3dtZWx0IG1vZHVsZSwgZmFjdG9ycyBzdWNoIGFzIGVsZXZhdGlvbiBhbmQgdmVnZXRhdGlvbiB3aWxsIGFmZmVjdCB0aGUgb2Ygc25vdy10by1ydW5vZmYgcmF0ZS4gU2ltaWxhcmx5LCB0ZW1wZXJhdHVyZSBhbmQgcHJlY2lwaXRhdGlvbiBkaWZmZXIgd2l0aCBlbGV2YXRpb24sIG1lYW5pbmcgdGhhdCBTTk9URUwgZGF0YSBmcm9tIGEgc2luZ2xlIGxvY2F0aW9uIG1heSBub3QgZnVsbHkgcmVwcmVzZW50IGNvbmRpdGlvbnMgYWNyb3NzIHRoZSBlbnRpcmUgd2F0ZXJzaGVkLgoKVG8gYWNjb3VudCBmb3IgdGhlc2UgdmFyaWF0aW9ucywgdGhlICJ3ZWlnaHRlZCIgdmFsdWVzIGZvciB0aGlzIGV4ZXJjaXNlIGhhdmUgYmVlbiBhZGp1c3RlZCB1c2luZyBsaW5lYXIgc2NhbGluZyByZWxhdGlvbnNoaXBzIHRoYXQgZXN0aW1hdGUgYXZlcmFnZSBjb25kaXRpb25zIGFjcm9zcyB0aGUgd2F0ZXJzaGVkLiBUaGUgYWRqdXN0bWVudHMgdXNlIGVsZXZhdGlvbi1wcmVjaXBpdGF0aW9uIGFuZCBlbGV2YXRpb24tdGVtcGVyYXR1cmUgcmVsYXRpb25zaGlwcyBkZXJpdmVkIGZyb20gaW52ZXJzZSBkaXN0YW5jZSB3ZWlnaHRpbmcgdG8gYmV0dGVyIGFwcHJveGltYXRlIHNwYXRpYWxseSBkaXN0cmlidXRlZCBoeWRyb2xvZ2ljYWwgaW5wdXRzIHJhdGhlciB0aGFuIHJlbHlpbmcgb24gYSBzaW5nbGUgcG9pbnQgbWVhc3VyZW1lbnQuCgovcHJlY2lwX3NwYXRpYWxfaW50ZXJwLnBuZwoKSWYgeW91IGFyZSBpbnRlcmVzdGVkLCB5b3UgY2FuIHN0YXJ0IGV4cGxvcmluZyBzcGF0aWFsIGludGVycG9sYXRpb24gd2l0aDoKMS4gVGhpZXNzZW4gcG9seWdvbnMKIVtUaGllc3NlbiBwb2x5Z29uc10oaHR0cHM6Ly91cGxvYWQud2lraW1lZGlhLm9yZy93aWtpcGVkaWEvY29tbW9ucy90aHVtYi9kL2Q5L1Zvcm9ub2lfZ3Jvd3RoX2V1Y2xpZGVhbi5naWYvNDQwcHgtVm9yb25vaV9ncm93dGhfZXVjbGlkZWFuLmdpZikKMi4gSW52ZXJzZSBkaXN0YW5jZSB3ZWlnaHRpbmcKMy4gS3JpbmdpbmcgbWV0aG9kcwp0byBkZXRlcm1pbmUgaWYgYW55IG9mIHRoZXNlIGFyZSBhcHBsaWNhYmxlIHRvIHlvdXIgc3R1ZHkgYXJlYS4KCk90aGVyIGNvbHVtbnMgaW4gdGhpcyBkYXRhIGluY2x1ZGU6CioqUV9tM19zIGFuZCBRX21tX2RheSoqIC0gRGlzY2hhcmdlIChRKSBjb2xsZWN0ZWQgYXQgdGhlIEZvb2wgQ3JlZWsgb3V0bGV0IGJ5IFVTRlMsIGluIHVuaXRzIG9mIGN1YmljIG1ldGVycyBwZXIgc2Vjb25kIGFuZCBtbSBwZXIgZGF5IGZyb20gQXByaWwgdW50aWwgT2N0b2Jlci4KKipUbWF4X2MsIFRtaW5fYyBhbmQgVG1lYW5fYyoqIC0gVHlwaWNhbGx5LCB3ZSBjb3VsZCBmaW5kIGRhaWx5IG1lYW4sIG1heCBhbmQgbWluaW11bSB0ZW1wZXJhdHVyZXMgaW4gdGhlIFNOT1RFTCBkYXRhc2V0cywgaG93ZXZlciwgdGhpcyBwYXJ0aWN1bGFyIHN0YXRpb24gaXMgbWlzc2luZyB0ZW1wZXJhdHVyZSBkYXRhIChkdWUgdG8gcmVzdHJpY3Rpb25zIG9uIHRlY2huaWNhbCBhY2Nlc3MgaW4gMjAyMCksIHNvIHdlIHJldHJpZXZlZCB0ZW1wZXJhdHVyZSBkYXRhIGZyb20gR3JpZE1FVCB0aHJvdWdoIFtDbGltYXRlIEVuZ2luZV0oaHR0cHM6Ly9hcHAuY2xpbWF0ZWVuZ2luZS5vcmcvY2xpbWF0ZUVuZ2luZSkuIFRoaXMgaGlnaGxpZ2h0cyB0aGUgaW1wb3J0YW5jZSBvZiBldmFsdWF0aW5nIGVhY2ggdmFyaWFibGUgZm9yIGNvbXBsZXRlbmVzcy4gSXQgd2lsbCBzYXZlIHlvdSB0aGUgaGVhZGFjaGUgb2YgcnVubmluZyB0aGUgZW50aXJlIHdvcmtmbG93LCBvbmx5IHRvIGZpbmQgdGhhdCBtb2RlbCBvdXRwdXRzIGNhbm5vdCBiZSBzaW11bGF0ZWQgZm9yIHRoZSBsYXRlciBoYWxmIG9mIDIwMjAgZHVlIHRvIG1pc3NpbmcgaW5wdXQgZGF0YS4KKipSSG1pbiwgUkhtYXgqKiAtIFJlbGF0aXZlIGh1bWlkaXR5IGRhaWx5IG1pbiBhbmQgbWF4LCBhbHNvIGZyb20gR3JpZE1FVCwgYWNjZXNzZWQgdGhyb3VnaCBDbGltYXRlIEVuZ2luZQoqKlNXRWRpZmYubW0sIFBkaWZmLm1tIGFuZCBydW5vZmZfaW5wdXQubW0qKiAtIGFsbCBkYWlseSBvdXRwdXRzIG9mIGEgdGVtcGVyYXR1cmUgYmFzZWQgc25vd21lbHQgbW9kZWwgKHRoZSBzYW1lIGFzIGluIHRoZSBzbm93bWVsdCBtb2R1bGUpLiBydW5vZmZfaW5wdXQgaXMgdGhlIGVzdGltYXRlZCBkYWlseSBpbnB1dCB0byB0aGUgc3RyZWFtIGZyb20gbWVsdGVkIHNub3cgYW5kIGxpcXVpZCBwcmVjaXBpdGF0aW9uIGNvbWJpbmVkLgoKKipRMSAoNCBwbnRzKSBHZW5lcmF0ZSBzY3JpcHQgKGluY2x1ZGluZyBwbG90cykgdGhhdCBjYW4gYmUgdXNlZCB0byBldmFsdWF0ZSB0aGUgc3RydWN0dXJlIG9mIHRoZSBkYXRhc2V0IGFuZCB0aGUgZHVyYXRpb24gYW5kIGNvbnNpc3RlbmN5IG9mIHRoZSBkYXRhLiBUaGUgc3VibWl0dGVkIHBsb3Qgc2hvdWxkIHNob3cgYXQgbGVhc3QgdHdvIHRpbWUgc2VyaWVzIG9mICdpbmRhdGEnICgyIHZhcmlhYmxlcyBvbiB5LCBkYXRlIG9uIHgpLCBidXQgYmUgc3VyZSB0byBjaGVjayBldmVyeSBjb2x1bW4gZm9yIHlvdXJzZWxmLiBEbyB5b3Ugc2VlIGFueSBwb3RlbnRpYWwgaXNzdWVzIGxpa2UgbWlzc2luZyBkYXRhIG9yIHVuZXhwZWN0ZWQgdmFsdWVzPyoqCkFOU1dFUjoKCgoKCktlZXAgaW4gbWluZCB0aGF0IHlvdSBjYW4gcGxvdCBtb3JlIHRoYW4gdHdvIHZhcmlhYmxlcyBpbiBhIHNpbmdsZSBwbG90LCBidXQgdGhleSB3aWxsIGJlIG1vc3QgaGVscGZ1bCBpZiB5b3UgZ3JvdXAgdmFyaWFibGVzIHdpdGggYSBzaW1pbGFyIHktc2NhbGUuIEZvciBleGFtcGxlLCBjdW11bGF0aXZlIHByZWNpcGl0YXRpb24gb3IgU1dFIHZhbHVlcyB3aWxsIGhhdmUgYSBkaWZmZXJlbnQgcmFuZ2UgdGhhbiB2YXJpYWJsZXMgdGhhdCByZXByZXNlbnQgZGFpbHkgbWVhc3VyZW1lbnRzIGxpa2UgJ2lucHV0X21tJy4gQWx0ZXJuYXRpdmVseSwgeW91IGNhbiBhZGQgYSBzZWNvbmRhcnkgeS1heGlzIHRvIHlvdXIgcGxvdC4KCmBgYHtyfQpCTEFOSyArCiAgZ2VvbV9wb2ludChhZXMoeCA9IGRhdGUsIHkgPSBydW5vZmZfaW5wdXQubW0sIGNvbG9yID0gInJ1bm9mZl9pbnB1dC5tbSIpLCBzaXplID0gMC41KSArICAjIEFzc2lnbiBhIGxhYmVsIGZvciBsZWdlbmQKICBnZW9tX3BvaW50KGFlcyh4ID0gZGF0ZSwgeSA9IFFfbW1fZGF5LCBjb2xvciA9ICJtbS9kYXkiKSwgc2l6ZSA9IDAuNSkgKyAgIyBBc3NpZ24gYSBkaWZmZXJlbnQgbGFiZWwKICBnZW9tX3BvaW50KGFlcyh4ID0gZGF0ZSwgeSA9IHdlaWdodGVkX3ByZWNpcC5tbSwgY29sb3IgPSAid2VpZ2h0ZWRfcHJlY2lwLm1tIiksIHNpemUgPSAwLjUpICsgICMgQXNzaWduIGEgZGlmZmVyZW50IGxhYmVsCiAgQkxBTksoYWVzKHggPSBkYXRlLCB5ID0gUGRpZmYubW0sIGNvbG9yID0gIlBkaWZmLm1tIiksIHNpemUgPSAwLjUpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygicnVub2ZmX2lucHV0Lm1tIiA9ICJibHVlIiwgIm1tL2RheSIgPSAicmVkIiwgIndlaWdodGVkX3ByZWNpcC5tbSIgPSAiZ3JlZW4iLCAiUGRpZmYubW0iID0gJ3B1cnBsZScpKSArICAjIEN1c3RvbWl6ZSBjb2xvcnMKICBsYWJzKGNvbG9yID0gIkRpc2NoYXJnZSBVbml0cyIpICsgICMgTGVnZW5kIHRpdGxlCiAgdGhlbWVfbWluaW1hbCgpCmBgYAoKIDIsOTMwbS4Kd2F0ZXJzaGVkX2FyZWFfbTIgPC0gMjY0MDAwMCAKCk5vdGUgdGhhdCB3aGlsZSB0aGUgc3RyZWFtIGlzIHNub3ctY292ZXJlZCwgdGhlcmUgYXJlIG5vIHN0YWdlL2Zsb3cgbWVhc3VyZW1lbnRzIGJlaW5nIG1hZGUgYXQgdGhpcyBzaXRlLiBGb3IgbWFueSBvZiBvdXIgY2FsY3VsYXRpb25zIHRvIHdvcmssIHdlIHdpbGwgbm90IHdhbnQgTkEgaW4gb3VyIGRhdGEgZnJhbWVzLiBJbiB0aGlzIGRhdGEgc2V0LCBpZiB3ZSB2aWV3IHRoZSB0YWJ1bGFyIGRhdGEsIHRoZSBlbmQgZGlzY2hhcmdlIHJlYWRpbmcgKFFfbW1fZGF5KSwgaXMgdmVyeSBzaW1pbGFyIHRvIHRoZSBmaXJzdCBpbiB0aGUgZm9sbG93aW5nIGNhbGVuZGFyIHllYXIuIEZvciB0aGlzIGV4YW1wbGUsIHdlIHdpbGwgdGhlbiBmaWxsIHRoZSBOQSB2YWx1ZXMgd2l0aCB0aGUgbWVhbiBvZiB0aGUgZmluYWwgYW5kIGZpcnN0IHJlYWRpbmdzIGZvciBlYWNoIHdpbnRlciAoT2N0IC0gQXByaWwpIE5BIHN0cmluZy4KCmBgYHtyfQojIFJhdGhlciB0aGFuIHNjcm9sbGluZyB0aHJvdWdoIGEgZGF0YWZyYW1lLCB0aGlzIGdpdmVzIHVzIGEgc3VtIG9mICdOQScgcm9zIGluIHRoaXMgY29sdW1uCnN1bShpcy5uYShpbmRhdGEkUV9tbV9kYXkpKQpgYGAKCmBgYHtyfQojIEZ1bmN0aW9uIHRvIGZpbGwgTkEgdmFsdWVzIGluIFFfbW1fZGF5IGR1cmluZyB3aW50ZXIgKE9jdCAtIEFwcikKZmlsbF9uYV93aW50ZXIgPC0gZnVuY3Rpb24oZGYpIHsKICBkZiA8LSBkZiAlPiUKICAgIGFycmFuZ2UoZGF0ZSkgJT4lICMgRW5zdXJlIGRhdGEgaXMgc29ydGVkCiAgICBtdXRhdGUoCiAgICAgIG1vbnRoID0gbW9udGgoZGF0ZSksCiAgICAgIGlzX3dpbnRlciA9IG1vbnRoICVpbiUgYygxMCwgMTEsIDEyLCAxLCAyLCAzLCA0KSAjIElkZW50aWZ5IHdpbnRlciBtb250aHMKICAgICkKICAKICAjIElkZW50aWZ5IE5BIHN0cmV0Y2hlcyBpbiB3aW50ZXIgbW9udGhzCiAgbmFfaW5kaWNlcyA8LSB3aGljaChpcy5uYShkZiRRX21tX2RheSkgJiBkZiRpc193aW50ZXIpCiAgCiAgZm9yIChpZHggaW4gbmFfaW5kaWNlcykgewogICAgIyBGaW5kIHRoZSBsYXN0IG5vbi1OQSBiZWZvcmUgdGhlIGN1cnJlbnQgTkEKICAgIHByZXZfdmFsdWUgPC0gZGYkUV9tbV9kYXlbbWF4KHdoaWNoKCFpcy5uYShkZiRRX21tX2RheVsxOihpZHggLSAxKV0pKSldCiAgICAKICAgICMgRmluZCB0aGUgbmV4dCBub24tTkEgYWZ0ZXIgdGhlIGN1cnJlbnQgTkEKICAgIG5leHRfdmFsdWUgPC0gZGYkUV9tbV9kYXlbbWluKHdoaWNoKCFpcy5uYShkZiRRX21tX2RheVsoaWR4ICsgMSk6bnJvdyhkZildKSkgKyBpZHgpXQogICAgCiAgICAjIFJlcGxhY2UgdGhlIE5BIHdpdGggdGhlIGF2ZXJhZ2Ugb2YgcHJldl92YWx1ZSBhbmQgbmV4dF92YWx1ZQogICAgaWYgKCFpcy5uYShwcmV2X3ZhbHVlKSAmICFpcy5uYShuZXh0X3ZhbHVlKSkgewogICAgICBkZiRRX21tX2RheVtpZHhdIDwtIChwcmV2X3ZhbHVlICsgbmV4dF92YWx1ZSkgLyAyCiAgICB9CiAgfQogIAogIHJldHVybihkZikKfQoKIyBBcHBseSB0aGUgZnVuY3Rpb24KaW5kYXRhIDwtIEJMQU5LKGluZGF0YSkKYGBgCgpMZXQncyB0cnkgb3VyIHF1aWNrIGNoZWNrIGFnYWluOiAKYGBge3J9CiMgTm93IHdlIHNob3VsZCBzZWUgemVybyBOQSBpbiB0aGlzIGNvbHVtbgpzdW0oaXMubmEoaW5kYXRhJFFfbW1fZGF5KSkKYGBgCgpOZXh0LCB3ZSBuZWVkIHRvIGFkZCBkYWlseSBwb3RlbnRpYWwgZXZhcG90cmFuc3BpcmF0aW9uIChQRVQpIHRvIHRoZSBkYXRhc2V0LiBUaGUgZXZhcG90cmFuc3BpcmF0aW9uIG1vZHVsZSBjb3ZlcmVkIHNvbWUgb2YgdGhlIG51bWVyb3VzIHByZS1idWlsdCBmdW5jdGlvbnMgYXZhaWxhYmxlIGluIHZhcmlvdXMgUiBwYWNrYWdlcyBkZXNpZ25lZCBmb3IgRVQgZXN0aW1hdGlvbi4gRm9yIGluc3RhbmNlLCB0aGUgJ0V2YXBvdHJhbnNwaXJhdGlvbicgcGFja2FnZSBwcm92aWRlcyBFVCBlc3RpbWF0ZXMgZGVyaXZlZCBmcm9tIGFwcHJveGltYXRlbHkgMjAgZGlzdGluY3QgZXF1YXRpb25zIG9yIHZhcmlhdGlvbnMuIFRoZXNlIGZ1bmN0aW9ucyByZXF1aXJlIHByZWNpc2UgZGF0YSBmb3JtYXR0aW5nIHRvIGVuc3VyZSBjb21wYXRpYmlsaXR5IHdpdGggdGhlIGZ1bmN0aW9uIGFyZ3VtZW50cy4gVG8gaGVscCB5b3Ugc3RydWN0dXJlIHlvdXIgZnVuY3Rpb24gaW5wdXRzIHNpbWlsYXJseSwgbWFueSBwYWNrYWdlcyBjb21lIHdpdGggZXhhbXBsZSBkYXRhc2V0cyBpbiB0aGVpciBkb2N1bWVudGF0aW9uLiBTUEVJIGlzIGFub3RoZXIgcGFja2FnZSB0aGF0IG9mZmVycyBFVCBmdW5jdGlvbnMuIFRoZSBnaXRodWIgcmVwb3NpdG9yeSBmb3IgdGhpcyBwYWNrYWdlIGhhcyBiZWVuIHVwZGF0ZWQgZmFpcmx5IHJlY2VudGx5LCB3aGljaCBjYW4gYmUgaW1wb3J0YW50IHRvIHZlcmlmeS4gCgpXZSBjaG9zZSB0byB3cml0ZSBvdXIgb3duIGZ1bmN0aW9uIGhlcmUgc28geW91IGNvdWxkICdzZWUgdW5kZXIgdGhlIGhvb2QnLiAgCk5vdCBhbGwgcGFja2FnZXMgYXJlIGVxdWFsbHkgbWFpbnRhaW5lZCwgYXMgdGhleSBhcmUgb2Z0ZW4gZGV2ZWxvcGVkIGJ5IHJlc2VhcmNoZXJzIG9yIG1vZGVsZXJzIHRvIGltcHJvdmUgdGhlIHJlcGVhdGFibHkgb2YgdGhlaXIgd29yaywgYW5kIGNvbnRyaWJ1dGUgdG8gdGhlIGJyb2FkZXIgc2NpZW50aWZpYyBjb21tdW5pdHkuIE9uY2UgZnVuZGluZyBjZWFzZXMsIG9yIGlmIHRoZSBvcmlnaW5hbCBkZXZlbG9wZXIgbW92ZXMgb24gdG8gbmV3IHByb2plY3RzLCBhIGN1c3RvbSBwYWNrYWdlIG1heSBubyBsb25nZXIgcmVjZWl2ZSB1cGRhdGVzIG9yIHN1cHBvcnQuIEFzIFIsIFJTdHVkaW8gYW5kIG90aGVyIHN1cHBvcnRpbmcgcGFja2FnZXMgYXJlIHVwZGF0ZWQsIGEgcGFja2FnZSBtYXkgYmVjb21lIGRlcHJlY2lhdGVkLiBJZiB0aGUgcGFja2FnZSBzdGlsbCBmdW5jdGlvbnMgY29ycmVjdGx5IGluIHlvdXIgY3VycmVudCBSIHZlcnNpb24gYW5kIGRlcGVuZGVuY2llcywgdGhlcmXigJlzIG5vIGltbWVkaWF0ZSByZWFzb24gdG8gc3RvcCB1c2luZyBpdC4gSG93ZXZlciwgaWYgeW91IGFyZSBjb25jZXJuZWQgdGhhdCBmdXR1cmUgdmVyc2lvbnMgb2YgUiBvciBkZXBlbmRlbmNpZXMgbWlnaHQgYnJlYWsgdGhlIHBhY2thZ2VzIHlvdSB1c2UsIHlvdSBjYW4gY2hlY2sgdGhlIGRldmVsb3BtZW50IGFuZCBtYWludGVuYW5jZSBoaXN0b3J5IG9mIGN1c3RvbSBvciBzcGVjaWFsaXplZCBwYWNrYWdlcyAob3Igd3JpdGUgYSBwYWNrYWdlIG9yIGZ1bmN0aW9uIGZvciB5b3Vyc2VsZiBhcyBleGVtcGxpZmllZCBiZWxvdyEpLgoKSGVyZSBpcyBvdXIgSGFyZ3JlYXZlcyBmdW5jdGlvbiwgYWRhcHRlZCBmcm9tIHRoZSAnRXZhcG90cmFuc3BpcmF0aW9uJyBwYWNrYWdlIHRvIG1pbmltaXplIHJlLWZvcm1hdHRpbmcgb2Ygb3VyIGRhdGFmcmFtZS4gCgpgYGB7cn0KIyBGdW5jdGlvbiB0byBjYWxjdWxhdGUgRVQKY2FsY3VsYXRlX0VUIDwtIGZ1bmN0aW9uKGRhdGEsIGNvbnN0YW50cywgdHMgPSAiZGFpbHkiLCBtZXNzYWdlID0gInllcyIsIHNhdmUuY3N2ID0gIm5vIiwgLi4uKSB7CiAgCiAgIyBDaGVjayBmb3IgcmVxdWlyZWQgZGF0YQogIGlmIChpcy5udWxsKGRhdGEkVG1heCkgfCBpcy5udWxsKGRhdGEkVG1pbikpIHsKICAgIHN0b3AoIlJlcXVpcmVkIGRhdGEgbWlzc2luZyBmb3IgJ1RtYXgnIGFuZCAnVG1pbicsIG9yICdUZW1wJyIpCiAgfQogIAogICMgSGFyZ3JlYXZlcy1TYW1hbmkgRVQgQ2FsY3VsYXRpb24KICBUYSA8LSAoZGF0YSRUbWF4ICsgZGF0YSRUbWluKSAvIDIKICBQIDwtIDEwMS4zICogKCgyOTMgLSAwLjAwNjUgKiBjb25zdGFudHMkRWxldikgLyAyOTMpIF4gNS4yNgogIGRlbHRhIDwtIDQwOTggKiAoMC42MTA4ICogZXhwKCgxNy4yNyAqIFRhKSAvIChUYSArIDIzNy4zKSkpIC8gKChUYSArIDIzNy4zKSBeIDIpCiAgZ2FtbWEgPC0gMC4wMDE2MyAqIFAgLyBjb25zdGFudHMkbGFtYmRhCiAgZF9yMiA8LSAxICsgMC4wMzMgKiBjb3MoMiAqIHBpIC8gMzY1ICogZGF0YSRKKQogIGRlbHRhMiA8LSAwLjQwOSAqIHNpbigyICogcGkgLyAzNjUgKiBkYXRhJEogLSAxLjM5KQogIHdfcyA8LSBhY29zKC10YW4oY29uc3RhbnRzJGxhdF9yYWQpICogdGFuKGRlbHRhMikpCiAgTiA8LSAyNCAvIHBpICogd19zCiAgUl9hIDwtICgxNDQwIC8gcGkpICogZF9yMiAqIGNvbnN0YW50cyRHc2MgKiAod19zICogc2luKGNvbnN0YW50cyRsYXRfcmFkKSAqIHNpbihkZWx0YTIpICsgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29zKGNvbnN0YW50cyRsYXRfcmFkKSAqIGNvcyhkZWx0YTIpICogc2luKHdfcykpCiAgQ19IUyA8LSAwLjAwMTg1ICogKGRhdGEkVG1heCAtIGRhdGEkVG1pbikgXiAyIC0gMC4wNDMzICogKGRhdGEkVG1heCAtIGRhdGEkVG1pbikgKyAwLjQwMjMKICBFVF9IUy5EYWlseSA8LSAwLjAxMzUgKiBDX0hTICogUl9hIC8gY29uc3RhbnRzJGxhbWJkYSAqIChkYXRhJFRtYXggLSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhJFRtaW4pIF4gMC41ICogKFRhICsgMTcuOCkKICBFVC5EYWlseSA8LSBFVF9IUy5EYWlseQogIAogICMgQ3JlYXRlIFllYXJNb250aCBDb2x1bW4KICBkYXRhJFllYXJNb250aCA8LSBhcy5EYXRlKHBhc3RlKHllYXIoZGF0YSREYXRlLmRhaWx5KSwgbW9udGgoZGF0YSREYXRlLmRhaWx5KSwgIjAxIiwgc2VwID0gIi0iKSkKICAKICAjIEFubnVhbCBhbmQgTW9udGhseSBBZ2dyZWdhdGlvbnMKICBFVC5Bbm51YWwgPC0gYWdncmVnYXRlKEVULkRhaWx5IH4geWVhcihZZWFyTW9udGgpLCBkYXRhID0gZGF0YSwgRlVOID0gc3VtKQogIEVULk1vbnRobHkgPC0gYWdncmVnYXRlKEVULkRhaWx5IH4gWWVhck1vbnRoLCBkYXRhID0gZGF0YSwgRlVOID0gc3VtKQogIAogICMgRVQgZm9ybXVsYXRpbmcKICBFVF9mb3JtdWxhdGlvbiA8LSAiSGFyZ3JlYXZlcy1TYW1hbmkiCiAgRVRfdHlwZSA8LSAiUmVmZXJlbmNlIENyb3AgRVQiCiAgcmVzdWx0cyA8LSBsaXN0KEVULkRhaWx5ID0gRVQuRGFpbHksIEVULk1vbnRobHkgPSBFVC5Nb250aGx5LCAKICAgICAgICAgICAgICAgICAgRVQuQW5udWFsID0gRVQuQW5udWFsLCBFVF9mb3JtdWxhdGlvbiA9IEVUX2Zvcm11bGF0aW9uLCAKICAgICAgICAgICAgICAgICAgRVRfdHlwZSA9IEVUX3R5cGUpCiAgCiAgIyBTYXZlIHRvIENTViBpZiByZXF1aXJlZAogIGlmIChzYXZlLmNzdiA9PSAieWVzIikgewogICAgZm9yIChpIGluIDE6bGVuZ3RoKHJlc3VsdHMpKSB7CiAgICAgIG5hbWVyIDwtIG5hbWVzKHJlc3VsdHNbaV0pCiAgICAgIHdyaXRlLnRhYmxlKGFzLmNoYXJhY3RlcihuYW1lciksIGZpbGUgPSAiRVRfSGFyZ3JlYXZlc1NhbWFuaS5jc3YiLCAKICAgICAgICAgICAgICAgICAgZGVjID0gIi4iLCBxdW90ZSA9IEZBTFNFLCBjb2wubmFtZXMgPSBGQUxTRSwgCiAgICAgICAgICAgICAgICAgIHJvdy5uYW1lcyA9IEYsIGFwcGVuZCA9IFRSVUUsIHNlcCA9ICIsIikKICAgICAgd3JpdGUudGFibGUoZGF0YS5mcmFtZShnZXQobmFtZXIsIHJlc3VsdHMpKSwgZmlsZSA9ICJFVF9IYXJncmVhdmVzU2FtYW5pLmNzdiIsIAogICAgICAgICAgICAgICAgICBjb2wubmFtZXMgPSBGLCBhcHBlbmQgPSBUUlVFLCBzZXAgPSAiLCIpCiAgICB9CiAgICBpbnZpc2libGUocmVzdWx0cykKICB9IGVsc2UgewogICAgcmV0dXJuKHJlc3VsdHMpCiAgfQp9CmBgYAoKTm93IHdlIHdpbGwgZm9ybWF0IHRoZSBpbnB1dHMgc28gdGhlIGRhdGEgaXMgZWFzaWx5IHJlYWQgYnkgdGhlIGZ1bmN0aW9uLCBhbmQgcnVuIHRoZSBmdW5jdGlvbi4KCmBgYHtyfQojIEZvcm1hdCBvdXIgZGF0YSB0byBmaXQgdGhlIGZ1bmN0aW9uClBFVF9kYXRhIDwtIGxpc3QoCiAgVG1heCA9IGluZGF0YSRUbWF4LAogIFRtaW4gPSBpbmRhdGEkVG1pbiwKICBKID0gYXMubnVtZXJpYyhmb3JtYXQoaW5kYXRhJGRhdGUsICIlaiIpKSwKICBEYXRlLmRhaWx5ID0gaW5kYXRhJGRhdGUKKQoKIyBEZWZpbmUgY29uc3RhbnRzCmNvbnN0YW50cyA8LSBsaXN0KAogIEVsZXYgPSAyOTAwLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIEVsZXZhdGlvbiBpbiBtZXRlcnMKICBsYW1iZGEgPSAyLjQ1LCAgICAgICAgICAgICAgICAgICAgICAgICAgIyBMYXRlbnQgaGVhdCBvZiB2YXBvcml6YXRpb24gaW4gTUoua2deLTEKICBsYXRfcmFkID0gMzkuODggKiBwaSAvIDE4MCwgICAgICAgICAgICAgIyBMYXRpdHVkZSBpbiByYWRpYW5zCiAgR3NjID0gMC4wODIwICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgU29sYXIgY29uc3RhbnQgaW4gTUoubV4tMi5taW5eLTEKKQoKUEVUX0hhcmdyZWF2ZXMgPC0gY2FsY3VsYXRlX0VUKAogIGRhdGEgPSBQRVRfZGF0YSwKICBjb25zdGFudHMgPSBjb25zdGFudHMsCiAgdHMgPSAiZGFpbHkiLCAgICAgICAgIyBPcHRpb25hbDsgZGVmYXVsdHMgdG8gImRhaWx5IgogIG1lc3NhZ2UgPSAieWVzIiwgICAgICMgT3B0aW9uYWw7IHByaW50cyBzdW1tYXJ5IAogIHNhdmUuY3N2ID0gIm5vIiAgICAgICMgT3B0aW9uYWw7IGRvIG5vdCBzYXZlIHJlc3VsdHMgdG8gYSBDU1YKKQpgYGAKCk5vdyB3ZSdsbCBhZGQgZGFpbHkgRVQgaW50byBvdXIgb3JpZ2luYWwgZGF0YWZyYW1lOgoKYGBge3J9ClBFVF9tbSA8LSBQRVRfSGFyZ3JlYXZlcyRFVC5EYWlseQojIHB1dCB0aGUgYXBwcm94aW1hdGVkIFBFVF9tbSBpbnRvIHRoZSBsYXJnZXIgaW5kYXRhIGRmCmluZGF0YSA8LSBjYmluZChpbmRhdGEsIFBFVF9tbSkgICN3aXRoIGNiaW5kCgpoZWFkKGluZGF0YSkKYGBgCgoqKlEyLiAoNCBwdHMpIEdlbmVyYXRlIGEgc3VtbWFyeSBkYXRhZnJhbWUgdGhhdCBzdW1tYXJpemVzIGNvbHVtbnMgb2YgJ2luZGF0YScgYnkgd2F0ZXIgeWVhciBhbmQgaGVscHMgeW91IGV2YWx1YXRlIHRoZSB3YXRlciBiYWxhbmNlIGZvciBlYWNoIHllYXIuIChJIHJlY29tbWVuZCBzdW1tYXJpemluZyBTV0UsIHByZWNpcGl0YXRpb24sIHJ1bm9mZiBpbnB1dCwgZGlzY2hhcmdlLCBhbmQgUEVUKSoqICBNYWtlIHN1cmUgeW91ciBzdW1tYXJ5IG1ha2VzIHNlbnNlLiBGb3IgZXhhbXBsZSwgc29tZSB2YXJpYWJsZXMgYXJlIG1vc3QgdXNlZnVsIHdoZW4gc3VtbWFyaXplZCBhcyBhIG1lYW4sIHdoaWxlIG90aGVycyBhcmUgbW9yZSBoZWxwZnVsIHdoZW4gdmlld2VkIGFzIGFuIGFubnVhbCBzdW0sIG1pbmltdW0gb3IgbWF4aW11bS4gSWYgeW91IGFyZSB1bnN1cmUgb2Ygd2hlcmUgdG8gc3RhcnQsIHRyeSB1c2luZyB1c2luZyBncm91cF9ieSgpIGFuZCBzdW1tYXJpemUoKS4KCmBgYHtyfQojIEFubnVhbCBzdW1tYXJ5IHN0YXRzCmluZGF0YV9hbmFseXNpcyA8LSBpbmRhdGEgJT4lCiAgc2VsZWN0KC1kYXRlKSAlPiUKICBCTEFOSyh3dHJfeXIpICU+JQogIEJMQU5LKAogICAgd2VpZ2h0ZWRfcHJlY2lwLm1tID0gc3VtKHdlaWdodGVkX3ByZWNpcC5tbSwgbmEucm0gPSBUUlVFKSwKICAgIFRtZWFuX2MgPSBtZWFuKFRtZWFuX2MsIG5hLnJtID0gVFJVRSksCiAgICBzd2UubW1fbWF4ID0gbWF4KHdlaWdodGVkX3N3ZS5tbSwgbmEucm0gPSBUUlVFKSwKICAgIHBjdW11bC5tbV9tYXggPSBtYXgod2VpZ2h0ZWRfcGN1bXVsLm1tLCBuYS5ybSA9IFRSVUUpLAogICAgVG1heCA9IG1heChUbWF4X2MsIG5hLnJtID0gVFJVRSksCiAgICBUbWluID0gbWluKFRtaW5fYywgbmEucm0gPSBUUlVFKSwKICAgIFFfbW1fc3VtID0gc3VtKFFfbW1fZGF5LCBuYS5ybSA9IFRSVUUpLAogICAgUEVUX21tX3N1bSA9IHN1bShQRVRfbW0sIG5hLnJtID0gVFJVRSksIAogICAgcnVub2ZmX2lucHV0Lm1tID0gc3VtKHJ1bm9mZl9pbnB1dC5tbSwgbmEucm0gPSBUUlVFKSwKICApCgppbmRhdGFfYW5hbHlzaXMKCmBgYAoKKipRMyAoMyBwdHMpIFRoZSBwcm92aWRlZCBQRVQgZGF0YSB3YXMgY2FsY3VsYXRlZCBqdXN0IHVzaW5nIG1pbiBhbmQgbWF4IGRhaWx5IGFpciB0ZW1wZXJhdHVyZSB1c2luZyBhIEhhcmdyZWF2ZXMgYXBwcm9hY2guIFZpZXcgeW91ciBhbm51YWwgdG90YWxzIGZvciBQRVQgYW5kIGNvbXBhcmUgaXQgdG8gdGhlIGFtb3VudCBvZiBwcmVjaXBpdGF0aW9uLiBBcmUgdGhvc2UgdmFsdWVzIHJlYXNvbmFibGU/IFdoYXQgY2FuIHlvdSBzYXkgYWJvdXQgdGhlIHRpbWluZyBvZiB3YXRlciBkZW1hbmQgKFBFVCkgYW5kIGF2YWlsYWJpbGl0eSAobWVsdCBhbmQgcmFpbik/IElNUE9SVEFOVDogVXNlIHJ1bm9mZl9pbnB1dF9tbSBoZXJlIGFuZCBleHBsYWluIHdoeSBpdCB3b3VsZG4ndCBtYWtlIHNlbnNlIHRvIHVzZSB3ZWlnaHRlZF9wcmVjaXAubW0uKiogIApBTlNXRVI6IAoKCgoKYGBge3J9CiMgWW91ciBzY3JpcHQgYmVsb3cgc2hvdWxkIGZpdCB5b3VyIHZhcmlhYmxlcyBmcm9tIHlvdXIgc3VtbWFyeSBkYXRhZnJhbWUgYWJvdmUuIEhlcmUgaXMgYW4gZXhhbXBsZSBvZiB3aGF0IGEgc2ltcGxlIHdhdGVyIGJhbGFuY2UgbWlnaHQgbG9vayBsaWtlIGlmIEkgbmFtZWQgbXkgc3VtbWFyeSBkYXRhZnJhbWUgaW5kYXRhX2FuYWx5c2lzOiAKCiMgQ2FsY3VsYXRlIHRoZSByZXNpZHVhbCB3YXRlciBhZnRlciBhY2NvdW50aW5nIGZvciBQRVQgYW5kIGRpc2NoYXJnZQpyZXNpZHVhbF93YXRlciA8LSBpbmRhdGFfYW5hbHlzaXMkcnVub2ZmX2lucHV0Lm1tIC0gKGluZGF0YV9hbmFseXNpcyRQRVRfbW1fc3VtICsgaW5kYXRhX2FuYWx5c2lzJFFfbW1fc3VtKQoKIyBWaWV3IHRoZSByZXNpZHVhbCBmb3IgZWFjaCB5ZWFyCnByaW50KHJlc2lkdWFsX3dhdGVyKQpgYGAKCkJ5IHN1YnRyYWN0aW5nIGRpc2NoYXJnZSBhbmQgUEVUIGZyb20gcnVub2ZmX2lucHV0LCB3ZeKAmXJlIGVzc2VudGlhbGx5IGV4YW1pbmluZyB0aGUgcmVzaWR1YWwgd2F0ZXIuIFRoaXMgY291bGQgcmVwcmVzZW50IHRoZSBhbW91bnQgb2Ygd2F0ZXIgYXZhaWxhYmxlIHRvIHRoZSBzeXN0ZW0gYWZ0ZXIgYWNjb3VudGluZyBmb3IgdGhlIGRlbWFuZCAoUEVUKSBhbmQgdGhlIG91dGZsb3cgKGRpc2NoYXJnZSkuCgoqKlE0ICg0cG50cykgQ29uc2lkZXIgdGhlIGV2YXBvdHJhbnNwaXJhdGlvbiBtb2R1bGUgYW5kIHRoZSBkaXNjdXNzaW9uIHBvdGVudGlhbCBhbmQgYWN0dWFsIGV2YXBvdHJhbnNwaXJhdGlvbi4gV2h5IGRvIHlvdSB0aGluayBQRVQgeWllbGRzIGVzdGltYXRlcyBvZiBuZWdhdGl2ZSByZXNpZHVhbCB3YXRlciBpbiB0aGlzIGhpZ2ggZWxldmF0aW9uLCBzZW1pLWFyaWQgc3lzdGVtPyoqCkFOU1dFUjoKCgoKCkFnYWluLCB5b3UgbWF5IGhhdmUgdG8gY2hhbmdlIHNvbWUgb2YgdGhlIHNjcmlwdCBiZWxvdyB0byBhY2NvbW1vZGF0ZSB5b3VyIHN1bW1hcnkgZGF0YWZyYW1lLCBhbmQgbm90IGV2ZXJ5IGNvbHVtbiB3aWxsIGJlIGhlbHBmdWwgZm9yIGEgc3lub3BzaXMgZmlndXJlLCBidXQgdGhlIG9iamVjdGl2ZSBpbiB0aGlzIGNodW5rIGlzIHRvIHByZXNlbnQgdGhlIGNvbHVtbiB2YWx1ZXMgb2YgeW91ciBzdW1tYXJ5IGRhdGFmcmFtZSBhcyBhIGJhciBjaGFydC4KCmBgYHtyfQojIG1ha2UgbG9uZyBmb3JtIHdpdGggUEVUc3VtIGFuZCBQc3VtIGFzIHRoZSBrZXktdmFsdWUgcGFpcnMgKGV4Y2x1ZGUgd3RyX3lyIGZyb20gKQpkYXRfc3VtX3Bsb3QgPC0gaW5kYXRhX2FuYWx5c2lzICU+JQogIHBpdm90X2xvbmdlcihuYW1lc190byA9ICAia2V5IiwgdmFsdWVzX3RvID0gICJ2YWx1ZSIsIC13dHJfeXIpCgojIGJhciBwbG90IHBmIFBFVCBhbmQgUCBmb3IgZWFjaCB5ZWFyCmdncGxvdChCTEFOSywgYWVzKHggPSBCTEFOSyB5ID0gdmFsdWUsIGZpbGwgPSBrZXkpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIikgKwogIGxhYnMoeCA9ICJXYXRlciBZZWFyIiwgeSA9ICJtbS95ZWFyIiwgZmlsbCA9IHt9KQpgYGAKCmBgYHtyfQojIyMgVElNSU5HCiMgY3JlYXRlIHdlZWtseSBtZWFucyBvciB0b3RhbHMgZm9yIGJvdGggdGltZSBzZXJpZXMgYW5kIHBsb3QgdGhlbSB0b2dldGhlciB0byBkZXRlcm1pbmUgdGhlIHRpbWluZyBvZiBlYWNoIApkYXRfd2Vla2x5IDwtIGluZGF0YSAlPiUKICBncm91cF9ieShXZWVrID0gd2VlayhkYXRlKSkgJT4lCiAgQkxBTksoCiAgICBQRVQgPSBzdW0oUEVUX21tKSwgCiAgICBQID0gc3VtKHJ1bm9mZl9pbnB1dC5tbSkKICAgICkgJT4lCiAgICBwaXZvdF9sb25nZXIobmFtZXNfdG8gPSAia2V5IiwgdmFsdWVzX3RvID0gInZhbHVlIiwgLVdlZWspCgojIGxpbmUgcGxvdCBvZiBQIGFuZCBQRVQgb24gYSB3ZWVrbHkgYmFzaXMuIFVzZSBkYXRfd2Vla2x5IGFzIHRoZSBkYXRhIHNvdXJjZS4KZ2dwbG90KGRhdF93ZWVrbHksIGFlcyh4ID0gV2VlaywgeSA9IHZhbHVlLCBjb2xvciA9IGtleSkpICsKICBCTEFOSygpICsgIyBjcmVhdGUgbGluZSBwbG90CiAgbGFicyh4ID0gIldlZWsgb2YgWWVhciIsIHkgPSAibW0veWVhciIsIGNvbG9yID0ge30pCmBgYAoKIyBTaW5nbGUgbW9kZWwgcnVuCkxvb2sgYXQgdGhlIHBhcmFtZXRlcnMgdG8gbWFrZSBzdXJlIHlvdSBrbm93IHdoYXQgZWFjaCBwYXJhbWV0ZXIgZG9lcy4gVGhlIHdheSB0aGUgbW9kZWwgaXMgc2V0IHVwLCBpcyB0aGF0IGV2ZXJ5dGhpbmcgaXMgaGlkZGVuIGluc2lkZSBhIGZ1bmN0aW9uLiBUaGUgdXNlciAoLS0+IHlvdSkgb25seSBmb3JtYXRzIHRoZSBpbnB1dCBkYXRhIGFuZCBwYXNzZXMgdGhlIHBhcmFtZXRlcnMgdG8gdGhlIGZ1bmN0aW9uLiBBbGwgbW9kZWwgb3V0cHV0IGlzIGNvbnRhaW5lZCBpbiAibW9kZWxSdW4iLiBJZiB5b3UgbG9vayBhdCB0aGUgRW52aXJvbm1lbnQsIHlvdSB3aWxsIG5vdGljZSB0aGF0IG1vZGVsUnVuIGlzIGEgbGlzdC4gQSBsaXN0IGlzIGV2ZW4gbW9yZSBmbGV4aWJsZSBpbiB0ZXJtcyBvZiBkYXRhIHN0b3JhZ2UgdGhhbiBhIGRhdGFmcmFtZSAoYSBkYXRhZnJhbWUgaXMgYWN0dWFsbHkgYSBzcGVjaWFsIHR5cGUgb2YgbGlzdC4uLikuIFdoaWxlIGxpc3RzIGFyZSBzdXBlciBmbGV4aWJsZSwgdGhleSBjYW4gYWxzbyBiZSBtb3JlIGN1bWJlcnNvbWUgdG8gZGVhbCB3aXRoLiBJIGluY2x1ZGVkIHNvbWUgY29kZSB0aGF0IHRha2VzIHRoZSBvdXRwdXQgZnJvbSB0aGUgbW9kZWwgcnVuIGFuZCBzYXZlcyBhbGwgdGhlIGltcG9ydGFudCBiaXRzIGFuZCBwaWVjZXMgaW4gYSBjb252ZW5pZW50IGRhdGFmcmFtZSBjYWxsZWQgSEJWUnVuLiBGb3IgdGhpcyBwYXJ0IChzaW5nbGUgbW9kZWwgcnVucyksIHlvdSB3aWxsIHJlYWxseSBvbmx5IG5lZWQgdGhlIGRhdGEgY29udGFpbmVkIGluIHRoZSBIQlZSdW4gZGF0YWZyYW1lLgogIAojIHNpbmdsZSBtb2RlbCBleGVjdXRpb24KYGBge3J9CiMgc2V0IHVwIHRoZSBwYXJhbWV0ZXIgdmVjdG9yCm1vZGVsX3BhcmFtcyA8LSBjKAogIDEuMDUsICMgU0NGIHNub3cgY29ycmVjdGlvbiBmYWN0b3IgWy1dIChlLmcuLCAwLjktMS41KTsKICAxLjgwLCAjIERERiBkZWdyZWUgZGF5IGZhY3RvciBbbW0vZGVnQy90aW1lc3RlcF0gKGUuZy4sIDAuMC01LjAgbW0vZGVnQy9kYXkpOwogIDIsICMgVHIgdGhyZXNob2xkIHRlbXBlcmF0dXJlIGFib3ZlIHdoaWNoIHByZWNpcGl0YXRpb24gaXMgcmFpbiBbZGVnQ10gKGUuZy4sIDEuMC0zLjAgZGVnQyk7CiAgMCwgIyBUcyB0aHJlc2hvbGQgdGVtcGVyYXR1cmUgYmVsb3cgd2hpY2ggcHJlY2lwaXRhdGlvbiBpcyBzbm93IFtkZWdDXSAoZS5nLiwgLTMuMC0xLjAgZGVnQyk7CiAgLTAuMzM2LCAjIFRtIHRocmVzaG9sZCB0ZW1wZXJhdHVyZSBhYm92ZSB3aGljaCBtZWx0IHN0YXJ0cyBbZGVnQ10gKGUuZy4sIC0yLjAtMi4wIGRlZ0MpOwogIDAuMiwgIyBMUHJhdCBwYXJhbWV0ZXIgcmVsYXRlZCB0byB0aGUgbGltaXQgZm9yIHBvdGVudGlhbCBldmFwb3JhdGlvbiBbLV0gKGUuZy4sIDAuMC0xLjApOwogIDEyMSwgIyBGQyBmaWVsZCBjYXBhY2l0eSwgaS5lLiwgbWF4IHNvaWwgbW9pc3R1cmUgc3RvcmFnZSBbbW1dIChlLmcuLCAwLTYwMCBtbSk7CiAgMi41MiwgIyBCRVRBIHRoZSBub24gbGluZWFyIHBhcmFtZXRlciBmb3IgcnVub2ZmIHByb2R1Y3Rpb24gWy1dIChlLmcuLCAwLjAtMjAuMCk7CiAgMC40NzMsICMgazAgc3RvcmFnZSBjb2VmZmljaWVudCBmb3IgdmVyeSBmYXN0IHJlc3BvbnNlIFt0aW1lc3RlcF0gKGUuZy4sIDAuMC0yLjAgZGF5cyk7CiAgOS4wNiwgIyBrMSBzdG9yYWdlIGNvZWZmaWNpZW50IGZvciBmYXN0IHJlc3BvbnNlIFt0aW1lc3RlcF0gKGUuZy4sIDIuMC0zMC4wIGRheXMpOwogIDE0MiwgIyBrMiBzdG9yYWdlIGNvZWZmaWNpZW50IGZvciBzbG93IHJlc3BvbnNlIFt0aW1lc3RlcF0gKGUuZy4sIDMwLjAtMjUwLjAgZGF5cyk7CiAgNTAuMSwgIyBsc3V6IHRocmVzaG9sZCBzdG9yYWdlIHN0YXRlLCBpLmUuLCB0aGUgdmVyeSBmYXN0IHJlc3BvbnNlIHN0YXJ0IGlmIGV4Y2VlZGVkIFttbV0gKGUuZy4sIDEuMC0xMDAuMCBtbSk7CiAgMi4zOCwgIyBjcGVyYyBjb25zdGFudCBwZXJjb2xhdGlvbiByYXRlIFttbS90aW1lc3RlcF0gKGUuZy4sIDAuMC04LjAgbW0vZGF5KTsKICAxMCwgIyBibWF4IG1heGltdW0gYmFzZSBhdCBsb3cgZmxvd3MgW3RpbWVzdGVwXSAoZS5nLiwgMC4wLTMwLjAgZGF5cyk7CiAgMjUgIyBjcm91dGUgZnJlZSBzY2FsaW5nIHBhcmFtZXRlciBbdGltZXN0ZXBeMi9tbV0gKGUuZy4sIDAuMC01MC4wIGRheXNeMi9tbSk7CikKCiMgc2V0IHRpbWUgcGVyaW9kCm1vZGVsX2luIDwtIGluZGF0YSAlPiUKICBmaWx0ZXIoZGF0ZSA+PSBhc19kYXRlKCIyMDE3LTEwLTAxIikgJiBkYXRlIDw9IGFzX2RhdGUoIjIwMjItMDktMzAiKSkKCiMgc2V0IHVwIHRoZSBtb2RlbAojIyBUSElTIElTIFRIRSBBQ1RVQUwgTU9ERUwgRVhFQ1VUSU9OCm1vZGVsUnVuIDwtIFRVV21vZGVsKAogIHByZWMgPSBtb2RlbF9pbiR3ZWlnaHRlZF9wcmVjaXAubW0sICMgcHJlY2lwIGlucHV0CiAgYWlydCA9IG1vZGVsX2luJFRtZWFuX2MsICMgYWlyIHRlbXAgaW5wdXQKICBlcCA9IG1vZGVsX2luJFBFVF9tbSwgIyBwZXQgaW5wdXQKICBhcmVhID0gMSwgIyBvbmUgem9uZSBmb3IgdGhlIGVudGlyZSB3YXRlcnNoZWQKICBwYXJhbSA9IG1vZGVsX3BhcmFtcyAjIGlucHV0IG1vZGVsIHBhcmFtZXRlcnMKKQoKCiMgZ2V0IGFsbCBvdXRwdXRzIGludG8gYSBuaWNlIGRmCkhCVlJ1biA8LSB0aWJibGUoCiAgRGF0ZSA9IG1vZGVsX2luJERhdGUsICMgZGF0ZQogIFBfbW0gPSBtb2RlbFJ1biRwcmVjLCAjIHByZWNpcAogIFRhaXIgPSBtb2RlbFJ1biRhaXJ0LCAjIGFpciB0ZW1wCiAgU1dFb2JzID0gbW9kZWxfaW4kd2VpZ2h0ZWRfc3dlLm1tLCAjIG9ic2VydmVkIHN3ZQogIFBFVCA9IG1vZGVsUnVuJGVwLCMgcGV0CiAgUW9icyA9IG1vZGVsX2luJFFfbW1fZGF5LCAjIG9ic2VydmVkIGRpc2NoYXJnZQogIFFzaW0gPSBtb2RlbFJ1biRxWzEsIF0sICMgc2ltdWxhdGVkIGRpc2NoYXJnZQogIFFzdXJmID0gbW9kZWxSdW4kcTBbMSwgXSwgIyBzdXJmYWNlIHJ1bm9mZgogIFFzdWJzdXJmID0gbW9kZWxSdW4kcTFbMSwgXSwgIyBzdWJzdXJmYWNlIGZsb3cKICBRYmFzZSA9IG1vZGVsUnVuJHEyWzEsIF0sICMgZ3JvdW5kd2F0ZXIgZmxvdwogIFJhaW4gPSBtb2RlbFJ1biRyYWluWzEsIF0sICMgc2ltdWxhdGVkIHJhaW4KICBTbm93ID0gbW9kZWxSdW4kc25vd1sxLCBdLCAjIHNpbXVsYXRlZCBzbm93ZmFsbAogIE1lbHQgPSBtb2RlbFJ1biRtZWx0WzEsIF0sICMgc2ltdWxhdGVkIG1lbHQKICBTV0VzaW0gPSBtb2RlbFJ1biRzd2VbMSwgXSwgIyBzaW11bGF0ZWQgc3dlCiAgU29pbG1vaXN0ID0gbW9kZWxSdW4kbW9pc3RbMSwgXSwgIyBzaW11bGF0ZWQgc29pbCBzdG9yYWdlCiAgQUVUID0gbW9kZWxSdW4kZXRhWzEsIF0sICMgc2ltdWxhdGVkIGV2YXBvdHJhbnNwaXJhdGlvbgogIFN0b3JhZ2VVcHBlciA9IG1vZGVsUnVuJHN1elsxLCBdLCAjIHVwcGVyIHN0b3JhZ2UgdmFsdWUKICBTdG9yYWdlTG93ZXIgPSBtb2RlbFJ1biRzbHpbMSwgXSAjIGxvd2VyIHN0b3JhZ2UgdmFsdWUKKQpgYGAKCiMjIyAgT2JqZWN0aXZlIGZ1bmN0aW9ucwojIyMjIEtHRQoKQmVmb3JlIHdlIGNhbiBzdGFydCB0cnlpbmcgdG8gdHVuZSBvdXIgbW9kZWwgdG8gbG9vayBtb3JlIGxpa2UgdGhlCm9ic2VydmVkIGRpc2NoYXJnZSByZWNvcmQsIGl0IHdvdWxkIGJlIGhlbHBmdWwgdG8gaGF2ZSBzb21lIHNvcnQgb2YKcXVhbnRpZmllZCBtZXRyaWMgZm9yIGhvdyB3ZWxsIG91ciBtb2RlbGVkIGRhdGEgZml0cyB0aGUgbWVhc3VyZWQgZGF0YS4KClRoZXJlIGFyZSBtYW55IGRpZmZlcmVudCB3YXlzIHRvIGRvIHRoaXMsIGJ1dCBkaXNjdXNzaW9uIG9mIHRoZSBwcm9zIGFuZCBjb25zIG9mIHRob3NlIGFwcHJvYWNoZXMgaXMgYmV5b25kIHRoaXMgcXVpY2sgaW50cm9kdWN0aW9uIHRvIG1vZGVsaW5nLgoKSGVyZSB3ZSB3aWxsIGRlbW9uc3RyYXRlIHRoZSBLbGluZy1HdXB0YSBlZmZpY2llbmN5IGJvdGggZm9yIHJ1bm9mZiBhcyB3ZWxsIGFzIGZvciBzd2UuCmBgYHtyfQojIHNlbGVjdCB0aGUgUW9icyBhbmQgUXNpbSB0aW1lc2VyaWVzCiMgRE9OJ1QgRk9SR0VUIFRPIEVYQ0xVREUgVEhFIEZJUlNUIFlFQVIKUW9icyA8LSBIQlZSdW4kUW9ic1szNjY6bGVuZ3RoKEhCVlJ1biRRb2JzKV0gIyBvYnNlcnZlZCBydW5vZmYgV0lUSE9VVCBXQVJNLVVQIFBFUklPRApRc2ltIDwtIEhCVlJ1biRRc2ltWzM2NjpsZW5ndGgoSEJWUnVuJFFzaW0pXSAjIHNpbXVsYXRlZCBydW5vZmYgV0lUSE9VVCBXQVJNLVVQIFBFUklPRAoKIyBLR0UKa2dlX3JfcSA8LSBjb3IoUW9icywgUXNpbSkKa2dlX2JldGFfcSA8LSBtZWFuKFFzaW0pIC8gbWVhbihRb2JzKQprZ2VfZ2FtbWFfcSA8LSAoc2QoUXNpbSkgLyBtZWFuKFFzaW0pKSAvIChzZChRb2JzKSAvIG1lYW4oUW9icykpCmtnZV9xIDwtIDEgLSBzcXJ0KChrZ2Vfcl9xIC0gMSleMiArIChrZ2VfYmV0YV9xIC0gMSleMiArIChrZ2VfZ2FtbWFfcSAtIDEpXjIpCmtnZV9xCmBgYAoKCmBgYHtyfQojIyBTbm93IC0gd2F0ZXIgZXF1aXZhbGVudApTV0VvYnMgPC0gSEJWUnVuJFNXRW9ic1szNjY6bGVuZ3RoKEhCVlJ1biRTV0VvYnMpXSAjIG9ic2VydmVkIHN3ZSBXSVRIT1VUIFdBUk0tVVAgUEVSSU9EClNXRXNpbSA8LSBIQlZSdW4kU1dFc2ltWzM2NjpsZW5ndGgoSEJWUnVuJFNXRW9icyldICMgc2ltdWxhdGVkIHN3ZSBXSVRIT1VUIFdBUk0tVVAgUEVSSU9ECgojIEtHRQprZ2Vfcl9zd2UgPC0gY29yKFNXRW9icywgU1dFc2ltKQprZ2VfYmV0YV9zd2UgPC0gbWVhbihTV0VzaW0pIC8gbWVhbihTV0VvYnMpCmtnZV9nYW1tYV9zd2UgPC0gKHNkKFNXRXNpbSkgLyBtZWFuKFNXRXNpbSkpIC8gKHNkKFNXRW9icykgLyBtZWFuKFNXRW9icykpCmtnZV9zd2UgPC0gMSAtIHNxcnQoKGtnZV9yX3N3ZSAtIDEpXjIgKyAoa2dlX2JldGFfc3dlIC0gMSleMiArIChrZ2VfZ2FtbWFfc3dlIC0gMSleMikKa2dlX3N3ZQpgYGAKCiMjIyBOU0UKTmFzaC1TdXRjbGlmZmUgRWZmaWNpZW5jeSAoTlNFKS4KCkJhc2ljYWxseSwgdGhlIE5TRSBsb29rcyBhdCBob3cgbXVjaCBiZXR0ZXIgeW91ciBtb2RlbCBydW4gZGlkIHRoYXQgaWYgeW91IGhhZCBqdXN0IHVzZWQgdGhlIG1lYW4gZGlzY2hhcmdlIGZvciB0aGUgZGF0YSByZWNvcmQgYXMgeW91cgoibW9kZWxsZWQgcmVzdWx0cyIuIEl0IGRvZXMgdGhpcyBieSBjb21wYXJpbmcgaG93IGZhciBvZmYgdGhlIG9ic2VydmVkIHZhbHVlcyB3aGVyZSBmcm9tIHRoZSBtZWFuIGRpc2NoYXJnZSB0byBob3cgZmFyIG9mZiB0aGUgbW9kZWxlZCB2YWx1ZXMgd2VyZSBmcm9tIHRoZSBvYnNlcnZlZCBkaXNjaGFyZ2UuCgpNYXRoZW1hdGljYWxseSwgTlNFIGlzIHRoZSBzdW0gb2YgdGhlIHNxdWFyZWQgZGlmZmVyZW5jZXMgYmV0d2VlbiB0aGUKbW9kZWxlZCBhbmQgb2JzZXJ2ZWQgZGlzY2hhcmdlIGRpdmlkZWQgYnkgdGhlIHN1bSBvZiB0aGUgc3F1YXJlZApkaWZmZXJlbmNlcyBiZXR3ZWVuIHRoZSBvYnNlcnZlZCBhbmQgbWVhbiBkaXNjaGFyZ2UsIHN1YnRyYWN0ZWQgYnkgMS4KCiQkCk5TRSA9IDEgLSBcZnJhY3tcc3VtX3t0ID0gMX1ee1R9eyhRX21edCAtIFFfb150KV4yfX17XHN1bV97dCA9IDF9XntUfXsoUV9vXnQgLSBcYmFye1Ffb30pXjJ9fQokJCBXaGVyZSAkUV9tXnQkIGlzIG1vZGVsZWQgZGlzY2hhcmdlIGF0IHRpbWUgdCwgJFFfb150JCBpcyBvYnNlcnZlZApkaXNjaGFyZ2UgYXQgdGltZSB0LCBhbmQgJFxiYXJ7UV9vfSQgaXMgbWVhbiBvYnNlcnZlZCBkaXNjaGFyZ2UuCgpgYGB7cn0KI0NhbGN1bGF0ZSBOU0UgZm9yIHNub3csIFNXRSBpcyBtb2RlbGVkLCBTVEEyIGlzIG1lYXN1cmVkCk5TRV9RIDwtIDEgLSAoKHN1bSgoSEJWUnVuJFFvYnMgLSBIQlZSdW4kUXNpbSkgXiAyKSkgLyAKICAgICAgICAgICAgICAgICBzdW0oKEhCVlJ1biRRc2ltIC0gbWVhbihIQlZSdW4kUXNpbSkpIF4gMikpCgpOU0VfUQpgYGAKCmBgYHtyfQojQ2FsY3VsYXRlIE5TRSBmb3Igc25vdywgU1dFIGlzIG1vZGVsZWQsIFNUQTIgaXMgbWVhc3VyZWQKTlNFc25vIDwtIDEgLSAoKHN1bSgoSEJWUnVuJFNXRW9icyAtIEhCVlJ1biRTV0VzaW0pIF4gMikpIC8gCiAgICAgICAgICAgICAgICAgc3VtKChIQlZSdW4kU1dFc2ltIC0gbWVhbihIQlZSdW4kU1dFc2ltKSkgXiAyKSkKCk5TRXNubwpgYGAKCiMjIENhbGlicmF0ZSBIQlYgbWFudWFsbHkKCldvb2hvbyEgV2UgY2FuIG5vdyBydW4gb3VyIG1vZGVsIGFuZCBhc3Nlc3MgaG93IHdlbGwgaXQgaXMgd29ya2luZyEKCk5vdywgbGV0J3Mgc2VlIGhvdyB3ZWxsIHdlIGNhbiBnZXQgaXQgdG8gd29yay4gVGhlIGNvZGUgYmVsb3cgcnVucyB0aGUgbW9kZWwsIHByb2R1Y2VzIGEgcGxvdCwgYW5kIGNhbGN1bGF0ZXMgdGhlIE5TRSBiYXNlZCBvbiBkaXNjaGFyZ2UuCgpgYGB7cn0KCiMgc2V0IHVwIHRoZSBwYXJhbWV0ZXIgdmVjdG9yCm1vZGVsX3BhcmFtcyA8LSBjKAogIDEuMDUsICMgU0NGIHNub3cgY29ycmVjdGlvbiBmYWN0b3IgWy1dIChlLmcuLCAwLjktMS41KTsKICAxLjgwLCAjIERERiBkZWdyZWUgZGF5IGZhY3RvciBbbW0vZGVnQy90aW1lc3RlcF0gKGUuZy4sIDAuMC01LjAgbW0vZGVnQy9kYXkpOwogIDIsICMgVHIgdGhyZXNob2xkIHRlbXBlcmF0dXJlIGFib3ZlIHdoaWNoIHByZWNpcGl0YXRpb24gaXMgcmFpbiBbZGVnQ10gKGUuZy4sIDEuMC0zLjAgZGVnQyk7CiAgMCwgIyBUcyB0aHJlc2hvbGQgdGVtcGVyYXR1cmUgYmVsb3cgd2hpY2ggcHJlY2lwaXRhdGlvbiBpcyBzbm93IFtkZWdDXSAoZS5nLiwgLTMuMC0xLjAgZGVnQyk7CiAgLTAuMzM2LCAjIFRtIHRocmVzaG9sZCB0ZW1wZXJhdHVyZSBhYm92ZSB3aGljaCBtZWx0IHN0YXJ0cyBbZGVnQ10gKGUuZy4sIC0yLjAtMi4wIGRlZ0MpOwogIDAuMiwgIyBMUHJhdCBwYXJhbWV0ZXIgcmVsYXRlZCB0byB0aGUgbGltaXQgZm9yIHBvdGVudGlhbCBldmFwb3JhdGlvbiBbLV0gKGUuZy4sIDAuMC0xLjApOwogIDEyMSwgIyBGQyBmaWVsZCBjYXBhY2l0eSwgaS5lLiwgbWF4IHNvaWwgbW9pc3R1cmUgc3RvcmFnZSBbbW1dIChlLmcuLCAwLTYwMCBtbSk7CiAgMi41MiwgIyBCRVRBIHRoZSBub24gbGluZWFyIHBhcmFtZXRlciBmb3IgcnVub2ZmIHByb2R1Y3Rpb24gWy1dIChlLmcuLCAwLjAtMjAuMCk7CiAgMC40NzMsICMgazAgc3RvcmFnZSBjb2VmZmljaWVudCBmb3IgdmVyeSBmYXN0IHJlc3BvbnNlIFt0aW1lc3RlcF0gKGUuZy4sIDAuMC0yLjAgZGF5cyk7CiAgOS4wNiwgIyBrMSBzdG9yYWdlIGNvZWZmaWNpZW50IGZvciBmYXN0IHJlc3BvbnNlIFt0aW1lc3RlcF0gKGUuZy4sIDIuMC0zMC4wIGRheXMpOwogIDE0MiwgIyBrMiBzdG9yYWdlIGNvZWZmaWNpZW50IGZvciBzbG93IHJlc3BvbnNlIFt0aW1lc3RlcF0gKGUuZy4sIDMwLjAtMjUwLjAgZGF5cyk7CiAgNTAuMSwgIyBsc3V6IHRocmVzaG9sZCBzdG9yYWdlIHN0YXRlLCBpLmUuLCB0aGUgdmVyeSBmYXN0IHJlc3BvbnNlIHN0YXJ0IGlmIGV4Y2VlZGVkIFttbV0gKGUuZy4sIDEuMC0xMDAuMCBtbSk7CiAgMi4zOCwgIyBjcGVyYyBjb25zdGFudCBwZXJjb2xhdGlvbiByYXRlIFttbS90aW1lc3RlcF0gKGUuZy4sIDAuMC04LjAgbW0vZGF5KTsKICAxMCwgIyBibWF4IG1heGltdW0gYmFzZSBhdCBsb3cgZmxvd3MgW3RpbWVzdGVwXSAoZS5nLiwgMC4wLTMwLjAgZGF5cyk7CiAgMjUgIyBjcm91dGUgZnJlZSBzY2FsaW5nIHBhcmFtZXRlciBbdGltZXN0ZXBeMi9tbV0gKGUuZy4sIDAuMC01MC4wIGRheXNeMi9tbSk7CikKCgojIHNldCB0aW1lIHBlcmlvZAptb2RlbF9pbiA8LSBpbmRhdGEgJT4lCiAgZmlsdGVyKGRhdGUgPj0gYXNfZGF0ZSgiMjAxNy0xMC0wMSIpICYgZGF0ZSA8PSBhc19kYXRlKCIyMDIyLTA5LTMwIikpCgojIHNldCB1cCB0aGUgbW9kZWwKIyMgVEhJUyBJUyBUSEUgQUNUVUFMIE1PREVMIEVYRUNVVElPTgptb2RlbFJ1biA8LSBUVVdtb2RlbCgKICBwcmVjID0gbW9kZWxfaW4kd2VpZ2h0ZWRfcHJlY2lwLm1tLCAjIHByZWNpcCBpbnB1dAogIGFpcnQgPSBtb2RlbF9pbiRUbWVhbl9jLCAjIGFpciB0ZW1wIGlucHV0CiAgZXAgPSBtb2RlbF9pbiRQRVRfbW0sICMgcGV0IGlucHV0CiAgYXJlYSA9IDEsICMgb25lIHpvbmUgZm9yIHRoZSBlbnRpcmUgd2F0ZXJzaGVkCiAgcGFyYW0gPSBtb2RlbF9wYXJhbXMgIyBpbnB1dCBtb2RlbCBwYXJhbWV0ZXJzCikKCgojIGdldCBhbGwgb3V0cHV0cyBpbnRvIGEgbmljZSBkZgpIQlZSdW4gPC0gdGliYmxlKAogIERhdGUgPSBtb2RlbF9pbiREYXRlLCAjIGRhdGUKICBQX21tID0gbW9kZWxSdW4kcHJlYywgIyBwcmVjaXAKICBUYWlyID0gbW9kZWxSdW4kYWlydCwgIyBhaXIgdGVtcAogIFNXRW9icyA9IG1vZGVsX2luJHdlaWdodGVkX3N3ZS5tbSwgIyBvYnNlcnZlZCBzd2UKICBQRVQgPSBtb2RlbFJ1biRlcCwjIHBldAogIFFvYnMgPSBtb2RlbF9pbiRRX21tX2RheSwgIyBvYnNlcnZlZCBkaXNjaGFyZ2UKICBRc2ltID0gbW9kZWxSdW4kcVsxLCBdLCAjIHNpbXVsYXRlZCBkaXNjaGFyZ2UKICBRc3VyZiA9IG1vZGVsUnVuJHEwWzEsIF0sICMgc3VyZmFjZSBydW5vZmYKICBRc3Vic3VyZiA9IG1vZGVsUnVuJHExWzEsIF0sICMgc3Vic3VyZmFjZSBmbG93CiAgUWJhc2UgPSBtb2RlbFJ1biRxMlsxLCBdLCAjIGdyb3VuZHdhdGVyIGZsb3cKICBSYWluID0gbW9kZWxSdW4kcmFpblsxLCBdLCAjIHNpbXVsYXRlZCByYWluCiAgU25vdyA9IG1vZGVsUnVuJHNub3dbMSwgXSwgIyBzaW11bGF0ZWQgc25vd2ZhbGwKICBNZWx0ID0gbW9kZWxSdW4kbWVsdFsxLCBdLCAjIHNpbXVsYXRlZCBtZWx0CiAgU1dFc2ltID0gbW9kZWxSdW4kc3dlWzEsIF0sICMgc2ltdWxhdGVkIHN3ZQogIFNvaWxtb2lzdCA9IG1vZGVsUnVuJG1vaXN0WzEsIF0sICMgc2ltdWxhdGVkIHNvaWwgc3RvcmFnZQogIEFFVCA9IG1vZGVsUnVuJGV0YVsxLCBdLCAjIHNpbXVsYXRlZCBldmFwb3RyYW5zcGlyYXRpb24KICBTdG9yYWdlVXBwZXIgPSBtb2RlbFJ1biRzdXpbMSwgXSwgIyB1cHBlciBzdG9yYWdlIHZhbHVlCiAgU3RvcmFnZUxvd2VyID0gbW9kZWxSdW4kc2x6WzEsIF0gIyBsb3dlciBzdG9yYWdlIHZhbHVlCikKCiNUcmltIG91dCB0aGUgd2FybSB1cCBwZXJpb2QKT3V0VHJpbSA8LSBIQlZSdW4gJT4lIHNsaWNlKDM2NjpuKCkpCgojQ2FsY3VsYXRlIE5TRQpOU0UgPC0gMSAtICgoc3VtKChPdXRUcmltJFFzaW0gLSBPdXRUcmltJFFvYnMpIF4gMikpIC8gCiAgICAgICAgICAgICAgICAgc3VtKChPdXRUcmltJFFvYnMgLSBtZWFuKE91dFRyaW0kUW9icykpIF4gMikpCgpwcmludChOU0UpCmBgYAoKIyMgUGxvdCBvYnNlcnZlZCBhbmQgbW9kZWwgc2ltdWxhdGlvbnMKCkdlbmVyYXRlIHBsb3RzIHRoYXQgaW5jbHVkZSBhbmQgY29tcGFyZSB0aGUgZGlmZmVyZW50IG1vZGVsZWQgZmx1eGVzIGZyb20geW91ciBiZXN0IE5TRS4gU29tZSBvZiB0aG9zZSBmbHV4ZXMgY2FuIGJlIGltbWVkaWF0ZWx5IGNvbXBhcmVkIHRvIG9ic2VydmVkIGRhdGEgKGUuZy4sIHJ1bm9mZiBvciBTV0UpLCB3aGlsZSBvdGhlcnMgb25seSBleGlzdCBpbiBzaW11bGF0ZWQgZm9ybSAoZS5nLiwgc3RvcmFnZXMgb3Igb3V0Zmxvd3Mgb2YgdGhlIHZhcmlvdXMgcnVub2ZmIGNvbXBvbmVudHMpIGFuZCBuZWVkIHRvIGJlIGFzc2Vzc2VkIHdpdGggdGhlIHBlcmNlcHR1YWwgbW9kZWwgaW4gbWluZC4gIApNYWtlIHN1cmUgdGhhdCB0aGUgYXhlcyBhcmUgcHJvcGVybHkgbGFiZWxlZCB3aGVuIHlvdSBjcmVhdGUgcGxvdHMuIFRoZSBzY3JpcHQgYmVsb3cgd2lsbCBnZXQgeW91IHN0YXJ0ZWQuIAoKYGBge3J9CiMgQWRkIGRhdGUgdG8gdGhlIEhCVlJ1biByZXN1bHQgdGliYmxlCkhCVlJ1biA8LSBhcy5kYXRhLmZyYW1lKEhCVlJ1bikKSEJWUnVuJERhdGUgPC0gbW9kZWxfaW4kZGF0ZQpzdHIoSEJWUnVuKQoKIyBSb3VuZCB0aGUgTlNFIGZvciBkaXNwbGF5Cm5zZV9sYWJlbCA8LSBwYXN0ZSgiTlNFID0iLCByb3VuZChOU0UsIDMpKQoKcV9wbG90IDwtIGdncGxvdChkYXRhID0gSEJWUnVuKSArCiAgZ2VvbV9saW5lKGFlcyh4ID0gRGF0ZSwgeSA9IFFvYnMsIGNvbG9yID0gIlFvYnMiKSkgKyAgIyBRb2JzCiAgZ2VvbV9saW5lKGFlcyh4ID0gRGF0ZSwgeSA9IFFzaW0sIGNvbG9yID0gIlFzaW0iKSkgKyAgIyBRc2ltCiAgYW5ub3RhdGUoInRleHQiLAogICAgICAgICAgIHggPSBtYXgoSEJWUnVuJERhdGUpIC0gMTAwLCAgIyBNb3ZlIGxhYmVsICMgZGF5cyBmcm9tIHRoZSBlbmQKICAgICAgICAgICB5ID0gbWF4KEhCVlJ1biRRb2JzLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgIGxhYmVsID0gbnNlX2xhYmVsLAogICAgICAgICAgIGhqdXN0ID0gMSwgdmp1c3QgPSAxLjUsIHNpemUgPSA1LCBmb250ZmFjZSA9ICJib2xkIikgKwogIGxhYnMoeCA9IE5VTEwsIHkgPSAiUSAobW0vZGF5KSIsIGNvbG9yID0gTlVMTCwgdGl0bGUgPSAiUW9icyBhbmQgUXNpbSIpCgoKIyBNYWtlIGl0IGludGVyYWN0aXZlIHdpdGggcGxvdGx5CmdncGxvdGx5KHFfcGxvdCkKCmBgYAoKKipRNi4gKDUgcHRzKSBXaGF0IGlzIHRoZSByb2xlIG9mIHRoZSBtb2RlbCBwYXJhbWV0ZXJzIGluIHJlcHJlc2VudGluZyBoeWRyb2xvZ2ljYWwgcHJvY2Vzc2VzPyBXaGF0IGlzIG9uZSBlZmZlY3RpdmUgbWV0aG9kIHRvIGNhbGlicmF0ZSB0aGVzZSBwYXJhbWV0ZXJzIHdpdGhvdXQgcmVseWluZyBvbiBtYW51YWwgYWRqdXN0bWVudD8qKgoKQW5zd2VyOiAgCgojIyMgTW9yZSBleHBsb3JhdG9yeS9kZW1vbnN0cmF0aXZlIHBsb3RzCgpgYGB7cn0KCiMjIERPTidUIGZvcmdldCB0byByZW1vdmUgdGhlIHdhcm0gdXAgcGVyaW9kIGlmIHlvdSB3YW50IHRvIGNhbGN1bGF0ZSBOU0Ugb3IgS0dFCiMgU3dlCnN3ZV9wbG90IDwtIGdncGxvdChkYXRhID0gSEJWUnVuKSArCiAgZ2VvbV9saW5lKGFlcyh4ID0gRGF0ZSwgeSA9IFNXRW9icywgY29sb3IgPSAiU1dFb2JzIikpICsgIyBTV0VvYnMKICBnZW9tX2xpbmUoYWVzKEJMQU5LKSkgKyAjIFNXRXNpbQogIGxhYnMoeCA9IHt9LCB5ID0gIlNXRSAobW0pIiwgY29sb3IgPSB7fSkKZ2dwbG90bHkoc3dlX3Bsb3QpCmBgYAoKCmBgYHtyfQojIFEwLCBRMSwgUTIKcV9idWNrZXRfcGxvdCA8LSBnZ3Bsb3QoZGF0YSA9IEhCVlJ1bikgKwogIGdlb21fbGluZShhZXMoeCA9IERhdGUsIHkgPSBRc3VyZiwgY29sb3IgPSAiUXN1cmYiKSkgKyAjIFFzdXJmCiAgZ2VvbV9saW5lKGFlcyh4ID0gRGF0ZSwgeSA9IFFzdWJzdXJmLCBjb2xvciA9ICJRc3Vic3VyZiIpKSArICNRc3Vic3VyZgogIGdlb21fbGluZShhZXMoeCA9IERhdGUsIHkgPSBRYmFzZSwgY29sb3IgPSAiUWJhc2UiKSkgKyAjIFFiYXNlCiAgbGFicyh4ID0ge30sIHkgPSAiUSAobW0pIiwgY29sb3IgPSB7fSwgdGl0bGUgPSAiUTAsIFExLCBhbmQgUTIiKQpnZ3Bsb3RseShxX2J1Y2tldF9wbG90KQpgYGAKCmBgYHtyfQojIFBFVCBhbmQgQUVUCnBldF9wbG90IDwtIGdncGxvdChkYXRhID0gSEJWUnVuKSArCiAgZ2VvbV9saW5lKGFlcyh4ID0gRGF0ZSwgeSA9IFBFVCwgY29sb3IgPSAiUEVUIikpICsgIyBQRVQKICBnZW9tX2xpbmUoYWVzKHggPSBEYXRlLCB5ID0gQUVULCBjb2xvciA9ICJBRVQiKSkgKyAjIEFFVAogIGxhYnMoeCA9IHt9LCB5ID0gIkZsdXggKG1tKSIsIGNvbG9yID0ge30sIHRpdGxlID0gIlBFVCBhbmQgQUVUIikKZ2dwbG90bHkocGV0X3Bsb3QpCmBgYAoKYGBge3J9CiMgU3RvcmFnZXMKc3RvcmFnZV9wbG90IDwtIGdncGxvdChkYXRhID0gSEJWUnVuKSArCiAgZ2VvbV9saW5lKGFlcyh4ID0gRGF0ZSwgeSA9IFNvaWxtb2lzdCwgY29sb3IgPSAiU29pbCBtb2lzdHVyZSBzdG9yYWdlIikpICsgIyBzb2lsIG1vaXN0dXJlIHN0b3JhZ2UKICBnZW9tX2xpbmUoYWVzKHggPSBEYXRlLCB5ID0gU3RvcmFnZVVwcGVyLCBjb2xvciA9ICJVcHBlciBzdG9yYWdlIikpICsgIyB1cHBlciBzdG9yYWdlCiAgZ2VvbV9saW5lKGFlcyh4ID0gRGF0ZSwgeSA9IFN0b3JhZ2VMb3dlciwgY29sb3IgPSAiTG93ZXIgc3RvcmFnZSIpKSArICMgbG93ZXIgc3RvcmFnZQogIGxhYnMoeCA9IHt9LCB5ID0gIlN0b3JhZ2UgKG1tKSIsIGNvbG9yID0ge30sIHRpdGxlID0gIlN0b3JhZ2VzIikKZ2dwbG90bHkoc3RvcmFnZV9wbG90KQpgYGAKCgo=